diff --git a/StudyFirst/.gitignore b/StudyFirst/.gitignore
new file mode 100644
index 0000000..a72d85d
--- /dev/null
+++ b/StudyFirst/.gitignore
@@ -0,0 +1,218 @@
+
+# Created by https://www.gitignore.io/api/kotlin,android,androidstudio
+# Edit at https://www.gitignore.io/?templates=kotlin,android,androidstudio
+
+### Android ###
+# Built application files
+*.apk
+*.ap_
+*.aab
+
+# Files for the ART/Dalvik VM
+*.dex
+
+# Java class files
+*.class
+
+# Generated files
+bin/
+gen/
+out/
+
+# Gradle files
+.gradle/
+build/
+
+# Local configuration file (sdk path, etc)
+local.properties
+
+# Proguard folder generated by Eclipse
+proguard/
+
+# Log Files
+*.log
+
+# Android Studio Navigation editor temp files
+.navigation/
+
+# Android Studio captures folder
+captures/
+
+# IntelliJ
+*.iml
+.idea/workspace.xml
+.idea/tasks.xml
+.idea/gradle.xml
+.idea/assetWizardSettings.xml
+.idea/dictionaries
+.idea/libraries
+.idea/caches
+# Android Studio 3 in .gitignore file.
+.idea/caches/build_file_checksums.ser
+.idea/modules.xml
+
+# Keystore files
+# Uncomment the following lines if you do not want to check your keystore files in.
+#*.jks
+#*.keystore
+
+# External native build folder generated in Android Studio 2.2 and later
+.externalNativeBuild
+
+# Google Services (e.g. APIs or Firebase)
+# google-services.json
+
+# Freeline
+freeline.py
+freeline/
+freeline_project_description.json
+
+# fastlane
+fastlane/report.xml
+fastlane/Preview.html
+fastlane/screenshots
+fastlane/test_output
+fastlane/readme.md
+
+# Version control
+vcs.xml
+
+# lint
+lint/intermediates/
+lint/generated/
+lint/outputs/
+lint/tmp/
+# lint/reports/
+
+### Android Patch ###
+gen-external-apklibs
+output.json
+
+### AndroidStudio ###
+# Covers files to be ignored for android development using Android Studio.
+
+# Built application files
+
+# Files for the ART/Dalvik VM
+
+# Java class files
+
+# Generated files
+
+# Gradle files
+.gradle
+
+# Signing files
+.signing/
+
+# Local configuration file (sdk path, etc)
+
+# Proguard folder generated by Eclipse
+
+# Log Files
+
+# Android Studio
+/*/build/
+/*/local.properties
+/*/out
+/*/*/build
+/*/*/production
+*.ipr
+*~
+*.swp
+
+# Android Patch
+
+# External native build folder generated in Android Studio 2.2 and later
+
+# NDK
+obj/
+
+# IntelliJ IDEA
+*.iws
+/out/
+
+# User-specific configurations
+.idea/caches/
+.idea/libraries/
+.idea/shelf/
+.idea/.name
+.idea/compiler.xml
+.idea/copyright/profiles_settings.xml
+.idea/encodings.xml
+.idea/misc.xml
+.idea/scopes/scope_settings.xml
+.idea/vcs.xml
+.idea/jsLibraryMappings.xml
+.idea/datasources.xml
+.idea/dataSources.ids
+.idea/sqlDataSources.xml
+.idea/dynamic.xml
+.idea/uiDesigner.xml
+
+# OS-specific files
+.DS_Store
+.DS_Store?
+._*
+.Spotlight-V100
+.Trashes
+ehthumbs.db
+Thumbs.db
+
+# Legacy Eclipse project files
+.classpath
+.project
+.cproject
+.settings/
+
+# Mobile Tools for Java (J2ME)
+.mtj.tmp/
+
+# Package Files #
+*.war
+*.ear
+
+# virtual machine crash logs (Reference: http://www.java.com/en/download/help/error_hotspot.xml)
+hs_err_pid*
+
+## Plugin-specific files:
+
+# mpeltonen/sbt-idea plugin
+.idea_modules/
+
+# JIRA plugin
+atlassian-ide-plugin.xml
+
+# Mongo Explorer plugin
+.idea/mongoSettings.xml
+
+# Crashlytics plugin (for Android Studio and IntelliJ)
+com_crashlytics_export_strings.xml
+crashlytics.properties
+crashlytics-build.properties
+fabric.properties
+
+### AndroidStudio Patch ###
+
+!/gradle/wrapper/gradle-wrapper.jar
+
+### Kotlin ###
+# Compiled class file
+
+# Log file
+
+# BlueJ files
+*.ctxt
+
+# Mobile Tools for Java (J2ME)
+
+# Package Files #
+*.jar
+*.nar
+*.zip
+*.tar.gz
+*.rar
+
+# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
+
+# End of https://www.gitignore.io/api/kotlin,android,androidstudio
\ No newline at end of file
diff --git a/StudyFirst/.gitignore.bak b/StudyFirst/.gitignore.bak
new file mode 100644
index 0000000..fd45b12
--- /dev/null
+++ b/StudyFirst/.gitignore.bak
@@ -0,0 +1,11 @@
+*.iml
+.gradle
+/local.properties
+/.idea/caches/build_file_checksums.ser
+/.idea/libraries
+/.idea/modules.xml
+/.idea/workspace.xml
+.DS_Store
+/build
+/captures
+.externalNativeBuild
diff --git a/StudyFirst/.idea/codeStyles/Project.xml b/StudyFirst/.idea/codeStyles/Project.xml
new file mode 100644
index 0000000..ce889bd
--- /dev/null
+++ b/StudyFirst/.idea/codeStyles/Project.xml
@@ -0,0 +1,119 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ xmlns:android
+
+ ^$
+
+
+
+
+
+
+
+
+ xmlns:.*
+
+ ^$
+
+
+ BY_NAME
+
+
+
+
+
+
+ .*:id
+
+ http://schemas.android.com/apk/res/android
+
+
+
+
+
+
+
+
+ .*:name
+
+ http://schemas.android.com/apk/res/android
+
+
+
+
+
+
+
+
+ name
+
+ ^$
+
+
+
+
+
+
+
+
+ style
+
+ ^$
+
+
+
+
+
+
+
+
+ .*
+
+ ^$
+
+
+ BY_NAME
+
+
+
+
+
+
+ .*
+
+ http://schemas.android.com/apk/res/android
+
+
+ ANDROID_ATTRIBUTE_ORDER
+
+
+
+
+
+
+ .*
+
+ .*
+
+
+ BY_NAME
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/StudyFirst/.idea/codeStyles/codeStyleConfig.xml b/StudyFirst/.idea/codeStyles/codeStyleConfig.xml
new file mode 100644
index 0000000..79ee123
--- /dev/null
+++ b/StudyFirst/.idea/codeStyles/codeStyleConfig.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/StudyFirst/.idea/runConfigurations.xml b/StudyFirst/.idea/runConfigurations.xml
new file mode 100644
index 0000000..7f68460
--- /dev/null
+++ b/StudyFirst/.idea/runConfigurations.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/StudyFirst/app/.gitignore b/StudyFirst/app/.gitignore
new file mode 100644
index 0000000..796b96d
--- /dev/null
+++ b/StudyFirst/app/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/StudyFirst/app/build.gradle b/StudyFirst/app/build.gradle
new file mode 100644
index 0000000..773569c
--- /dev/null
+++ b/StudyFirst/app/build.gradle
@@ -0,0 +1,59 @@
+apply plugin: 'com.android.application'
+
+apply plugin: 'kotlin-android'
+
+apply plugin: 'kotlin-android-extensions'
+
+apply plugin: 'kotlin-kapt'
+
+android {
+ compileSdkVersion 29
+ defaultConfig {
+ applicationId "sample.nackun.com.studyfirst"
+ minSdkVersion 21
+ targetSdkVersion 29
+ versionCode 1
+ versionName "1.0"
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ }
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ }
+ }
+ dataBinding {
+ enabled = true
+ }
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+}
+
+dependencies {
+ implementation fileTree(dir: 'libs', include: ['*.jar'])
+ implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
+
+ androidTestImplementation 'androidx.test.ext:junit:1.1.1'
+ androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
+
+ implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
+
+ implementation 'com.google.android.material:material:1.2.0-alpha04'
+ implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
+
+ implementation 'com.squareup.retrofit2:retrofit:2.7.0'
+ implementation 'com.squareup.retrofit2:converter-gson:2.6.2'
+
+ implementation 'org.koin:koin-android:2.0.1'
+ implementation 'org.koin:koin-androidx-viewmodel:2.0.1'
+
+ implementation 'io.reactivex.rxjava2:rxjava:2.2.16'
+ implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
+ implementation 'com.squareup.retrofit2:adapter-rxjava2:2.7.0'
+
+ implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.3"
+ implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.3"
+ implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0"
+}
diff --git a/StudyFirst/app/proguard-rules.pro b/StudyFirst/app/proguard-rules.pro
new file mode 100644
index 0000000..f1b4245
--- /dev/null
+++ b/StudyFirst/app/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/StudyFirst/app/src/androidTest/java/sample/nackun/com/studyfirst/ExampleInstrumentedTest.kt b/StudyFirst/app/src/androidTest/java/sample/nackun/com/studyfirst/ExampleInstrumentedTest.kt
new file mode 100644
index 0000000..c144a01
--- /dev/null
+++ b/StudyFirst/app/src/androidTest/java/sample/nackun/com/studyfirst/ExampleInstrumentedTest.kt
@@ -0,0 +1,22 @@
+package sample.nackun.com.studyfirst
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.platform.app.InstrumentationRegistry
+import org.junit.Assert.assertEquals
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+@RunWith(AndroidJUnit4::class)
+class ExampleInstrumentedTest {
+ @Test
+ fun useAppContext() {
+ // Context of the app under test.
+ val appContext = InstrumentationRegistry.getInstrumentation()
+ assertEquals("sample.nackun.com.studyfirst", appContext.context)
+ }
+}
diff --git a/StudyFirst/app/src/main/AndroidManifest.xml b/StudyFirst/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..a46576e
--- /dev/null
+++ b/StudyFirst/app/src/main/AndroidManifest.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/MainApplication.kt b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/MainApplication.kt
new file mode 100644
index 0000000..24f1118
--- /dev/null
+++ b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/MainApplication.kt
@@ -0,0 +1,30 @@
+package sample.nackun.com.studyfirst
+
+import android.app.Application
+import org.koin.android.ext.koin.androidContext
+import org.koin.core.context.startKoin
+import sample.nackun.com.studyfirst.data.di.networkModule
+import sample.nackun.com.studyfirst.data.di.remoteModule
+import sample.nackun.com.studyfirst.data.di.repositoryModule
+import sample.nackun.com.studyfirst.domain.di.useCaseModule
+import sample.nackun.com.studyfirst.presentation.di.viewModelModule
+
+@Suppress("unused")
+class MainApplication : Application() {
+
+ override fun onCreate() {
+ super.onCreate()
+ startKoin {
+ androidContext(this@MainApplication)
+ modules(
+ listOf(
+ useCaseModule,
+ networkModule,
+ repositoryModule,
+ remoteModule,
+ viewModelModule
+ )
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/api/BithumbApi.kt b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/api/BithumbApi.kt
new file mode 100644
index 0000000..19aa953
--- /dev/null
+++ b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/api/BithumbApi.kt
@@ -0,0 +1,13 @@
+package sample.nackun.com.studyfirst.data.api
+
+import retrofit2.http.GET
+import retrofit2.http.Path
+import sample.nackun.com.studyfirst.data.model.BithumbResult
+
+interface BithumbApi {
+ @GET("public/ticker/ALL")
+ suspend fun requestAllTicker(): BithumbResult
+
+ @GET("public/ticker/{currency}")
+ suspend fun requestTicker(@Path("currency") currency: String): BithumbResult
+}
\ No newline at end of file
diff --git a/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/api/CoinOneApi.kt b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/api/CoinOneApi.kt
new file mode 100644
index 0000000..2ed5ae5
--- /dev/null
+++ b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/api/CoinOneApi.kt
@@ -0,0 +1,13 @@
+package sample.nackun.com.studyfirst.data.api
+
+import retrofit2.http.GET
+import retrofit2.http.Query
+import sample.nackun.com.studyfirst.data.model.CoinOneTicker
+
+interface CoinOneApi {
+ @GET("/ticker?currency=all")
+ suspend fun requestAllTicker(): Map
+
+ @GET("/ticker")
+ suspend fun requestTicker(@Query("currency") currency: String): CoinOneTicker
+}
\ No newline at end of file
diff --git a/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/api/UpbitApi.kt b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/api/UpbitApi.kt
new file mode 100644
index 0000000..8926751
--- /dev/null
+++ b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/api/UpbitApi.kt
@@ -0,0 +1,14 @@
+package sample.nackun.com.studyfirst.data.api
+
+import retrofit2.http.GET
+import retrofit2.http.Query
+import sample.nackun.com.studyfirst.data.model.UpbitMarket
+import sample.nackun.com.studyfirst.data.model.UpbitTicker
+
+interface UpbitApi {
+ @GET("v1/market/all")
+ suspend fun requestMarket(): List
+
+ @GET("v1/ticker/")
+ suspend fun requestTicker(@Query("markets") markets: String): List
+}
\ No newline at end of file
diff --git a/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/di/NetworkModule.kt b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/di/NetworkModule.kt
new file mode 100644
index 0000000..bd7ff48
--- /dev/null
+++ b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/di/NetworkModule.kt
@@ -0,0 +1,26 @@
+package sample.nackun.com.studyfirst.data.di
+
+import org.koin.dsl.module
+import retrofit2.CallAdapter
+import retrofit2.Converter
+import retrofit2.Retrofit
+import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
+import retrofit2.converter.gson.GsonConverterFactory
+
+val networkModule = module {
+ factory { (baseUrl: String) ->
+ Retrofit.Builder()
+ .baseUrl(baseUrl)
+ .addConverterFactory(get())
+ .addCallAdapterFactory(get())
+ .build()
+ }
+
+ single {
+ GsonConverterFactory.create() as Converter.Factory
+ }
+
+ single {
+ RxJava2CallAdapterFactory.create() as CallAdapter.Factory
+ }
+}
\ No newline at end of file
diff --git a/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/di/RemoteModule.kt b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/di/RemoteModule.kt
new file mode 100644
index 0000000..276dee1
--- /dev/null
+++ b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/di/RemoteModule.kt
@@ -0,0 +1,23 @@
+package sample.nackun.com.studyfirst.data.di
+
+import org.koin.core.parameter.parametersOf
+import org.koin.dsl.module
+import retrofit2.Retrofit
+import sample.nackun.com.studyfirst.data.source.bithumb.BithumbDataSource
+import sample.nackun.com.studyfirst.data.source.bithumb.remote.BithumbRemoteDataSource
+import sample.nackun.com.studyfirst.data.source.coinone.remote.CoinOneRemoteDataSource
+import sample.nackun.com.studyfirst.data.source.upbit.CoinOneDataSource
+import sample.nackun.com.studyfirst.data.source.upbit.UpbitDataSource
+import sample.nackun.com.studyfirst.data.source.upbit.remote.UpbitRemoteDataSource
+import sample.nackun.com.studyfirst.data.api.BithumbApi
+import sample.nackun.com.studyfirst.data.api.CoinOneApi
+import sample.nackun.com.studyfirst.data.api.UpbitApi
+
+val remoteModule = module {
+ single { get { parametersOf("https://api.upbit.com") }.create(UpbitApi::class.java) }
+ single { get { parametersOf("https://api.bithumb.com") }.create(BithumbApi::class.java) }
+ single { get { parametersOf("https://api.coinone.co.kr") }.create(CoinOneApi::class.java) }
+ single { UpbitRemoteDataSource(get()) }
+ single { BithumbRemoteDataSource(get()) }
+ single { CoinOneRemoteDataSource(get()) }
+}
\ No newline at end of file
diff --git a/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/di/RepositoryModule.kt b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/di/RepositoryModule.kt
new file mode 100644
index 0000000..0b591d2
--- /dev/null
+++ b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/di/RepositoryModule.kt
@@ -0,0 +1,27 @@
+package sample.nackun.com.studyfirst.data.di
+
+import org.koin.dsl.module
+import sample.nackun.com.studyfirst.data.source.bithumb.BithumbRepository
+import sample.nackun.com.studyfirst.data.source.bithumb.BithumbRepositoryImpl
+import sample.nackun.com.studyfirst.data.source.upbit.CoinOneRepository
+import sample.nackun.com.studyfirst.data.source.upbit.CoinOneRepositoryImpl
+import sample.nackun.com.studyfirst.data.source.upbit.UpbitRepository
+import sample.nackun.com.studyfirst.data.source.upbit.UpbitRepositoryImpl
+
+val repositoryModule = module {
+ single {
+ UpbitRepositoryImpl(
+ get()
+ )
+ }
+ single {
+ BithumbRepositoryImpl(
+ get()
+ )
+ }
+ single {
+ CoinOneRepositoryImpl(
+ get()
+ )
+ }
+}
\ No newline at end of file
diff --git a/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/model/BithumbResult.kt b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/model/BithumbResult.kt
new file mode 100644
index 0000000..ed5e80c
--- /dev/null
+++ b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/model/BithumbResult.kt
@@ -0,0 +1,10 @@
+package sample.nackun.com.studyfirst.data.model
+
+import com.google.gson.annotations.SerializedName
+
+data class BithumbResult(
+ @SerializedName("data")
+ val bithumbData: Map,
+ @SerializedName("status")
+ val status: String
+)
\ No newline at end of file
diff --git a/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/model/BithumbTicker.kt b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/model/BithumbTicker.kt
new file mode 100644
index 0000000..442a204
--- /dev/null
+++ b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/model/BithumbTicker.kt
@@ -0,0 +1,26 @@
+package sample.nackun.com.studyfirst.data.model
+
+import com.google.gson.annotations.SerializedName
+
+data class BithumbTicker(
+// 최근 24시간 거래금액 = "acc_trade_value_24H"
+ @SerializedName("acc_trade_value_24H")
+ val accTradeValue24H: Double,
+// 최근 24시간 변동가 ="fluctate_24H"
+ @SerializedName("fluctate_24H")
+ val fluctate24H: Double,
+// 종목 구분 코드 = "market"
+ private var market: String,
+// 전일종가 = "prev_closing_price"
+ @SerializedName("prev_closing_price")
+ val prevClosingPrice: Double,
+// 종가 00시 기준 = "closing_price"
+ @SerializedName("closing_price")
+ val closingPrice: Double
+) {
+ fun setMarket(market: String) {
+ this.market = market
+ }
+
+ fun getMarket() = market
+}
\ No newline at end of file
diff --git a/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/model/CoinOneTicker.kt b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/model/CoinOneTicker.kt
new file mode 100644
index 0000000..d483d3d
--- /dev/null
+++ b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/model/CoinOneTicker.kt
@@ -0,0 +1,28 @@
+package sample.nackun.com.studyfirst.data.model
+
+import com.google.gson.annotations.SerializedName
+
+data class CoinOneTicker(
+ @SerializedName("currency")
+ val currency: String,
+ @SerializedName("first")
+ val first: String,
+ @SerializedName("high")
+ val high: String,
+ @SerializedName("last")
+ val last: String,
+ @SerializedName("low")
+ val low: String,
+ @SerializedName("volume")
+ val volume: String,
+ @SerializedName("yesterday_first")
+ val yesterdayFirst: String,
+ @SerializedName("yesterday_high")
+ val yesterdayHigh: String,
+ @SerializedName("yesterday_last")
+ val yesterdayLast: String,
+ @SerializedName("yesterday_low")
+ val yesterdayLow: String,
+ @SerializedName("yesterday_volume")
+ val yesterdayVolume: String
+)
\ No newline at end of file
diff --git a/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/model/UpbitMarket.kt b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/model/UpbitMarket.kt
new file mode 100644
index 0000000..88bf088
--- /dev/null
+++ b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/model/UpbitMarket.kt
@@ -0,0 +1,8 @@
+package sample.nackun.com.studyfirst.data.model
+
+import com.google.gson.annotations.SerializedName
+
+data class UpbitMarket(
+ @SerializedName("market")
+ val market: String
+)
\ No newline at end of file
diff --git a/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/model/UpbitTicker.kt b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/model/UpbitTicker.kt
new file mode 100644
index 0000000..d11f0bc
--- /dev/null
+++ b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/model/UpbitTicker.kt
@@ -0,0 +1,21 @@
+package sample.nackun.com.studyfirst.data.model
+
+import com.google.gson.annotations.SerializedName
+
+data class UpbitTicker(
+ //24시간 누적 거래대금
+ @SerializedName("acc_trade_price_24h")
+ val accTradePrice24h: Double,
+ //변화액의 절대값
+ @SerializedName("change_price")
+ val changePrice: Double,
+ //종목 구분 코드
+ @SerializedName("market")
+ val market: String,
+ //전일 종가
+ @SerializedName("prev_closing_price")
+ val prevClosingPrice: Double,
+ //종가
+ @SerializedName("trade_price")
+ val tradePrice: Double
+)
\ No newline at end of file
diff --git a/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/source/bithumb/BithumbDataSource.kt b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/source/bithumb/BithumbDataSource.kt
new file mode 100644
index 0000000..c39a41d
--- /dev/null
+++ b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/source/bithumb/BithumbDataSource.kt
@@ -0,0 +1,8 @@
+package sample.nackun.com.studyfirst.data.source.bithumb
+
+import sample.nackun.com.studyfirst.data.model.BithumbResult
+
+interface BithumbDataSource {
+ suspend fun requestAllTicker(): BithumbResult
+ suspend fun requestTicker(currency: String): BithumbResult
+}
\ No newline at end of file
diff --git a/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/source/bithumb/BithumbRepository.kt b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/source/bithumb/BithumbRepository.kt
new file mode 100644
index 0000000..c62414c
--- /dev/null
+++ b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/source/bithumb/BithumbRepository.kt
@@ -0,0 +1,8 @@
+package sample.nackun.com.studyfirst.data.source.bithumb
+
+import sample.nackun.com.studyfirst.data.model.BithumbResult
+
+interface BithumbRepository {
+ suspend fun requestAllTicker(): BithumbResult
+ suspend fun requestTicker(currency: String): BithumbResult
+}
\ No newline at end of file
diff --git a/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/source/bithumb/BithumbRepositoryImpl.kt b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/source/bithumb/BithumbRepositoryImpl.kt
new file mode 100644
index 0000000..25e6b58
--- /dev/null
+++ b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/source/bithumb/BithumbRepositoryImpl.kt
@@ -0,0 +1,11 @@
+package sample.nackun.com.studyfirst.data.source.bithumb
+
+class BithumbRepositoryImpl(
+ private val remoteDataSource: BithumbDataSource
+) : BithumbRepository {
+ override suspend fun requestTicker(currency: String) =
+ remoteDataSource.requestTicker(currency)
+
+ override suspend fun requestAllTicker() =
+ remoteDataSource.requestAllTicker()
+}
\ No newline at end of file
diff --git a/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/source/bithumb/remote/BithumbRemoteDataSource.kt b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/source/bithumb/remote/BithumbRemoteDataSource.kt
new file mode 100644
index 0000000..f0c64f4
--- /dev/null
+++ b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/source/bithumb/remote/BithumbRemoteDataSource.kt
@@ -0,0 +1,14 @@
+package sample.nackun.com.studyfirst.data.source.bithumb.remote
+
+import sample.nackun.com.studyfirst.data.source.bithumb.BithumbDataSource
+import sample.nackun.com.studyfirst.data.api.BithumbApi
+
+class BithumbRemoteDataSource(
+ private val retrofitService: BithumbApi
+) : BithumbDataSource {
+ override suspend fun requestTicker(currency: String) =
+ retrofitService.requestTicker(currency)
+
+ override suspend fun requestAllTicker() =
+ retrofitService.requestAllTicker()
+}
\ No newline at end of file
diff --git a/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/source/coinone/CoinOneDataSource.kt b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/source/coinone/CoinOneDataSource.kt
new file mode 100644
index 0000000..a514522
--- /dev/null
+++ b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/source/coinone/CoinOneDataSource.kt
@@ -0,0 +1,8 @@
+package sample.nackun.com.studyfirst.data.source.upbit
+
+import sample.nackun.com.studyfirst.data.model.CoinOneTicker
+
+interface CoinOneDataSource {
+ suspend fun requestAllTicker(): Map
+ suspend fun requestTicker(currency: String): CoinOneTicker
+}
\ No newline at end of file
diff --git a/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/source/coinone/CoinOneRepository.kt b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/source/coinone/CoinOneRepository.kt
new file mode 100644
index 0000000..42bedc5
--- /dev/null
+++ b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/source/coinone/CoinOneRepository.kt
@@ -0,0 +1,8 @@
+package sample.nackun.com.studyfirst.data.source.upbit
+
+import sample.nackun.com.studyfirst.data.model.CoinOneTicker
+
+interface CoinOneRepository {
+ suspend fun requestAllTicker(): Map
+ suspend fun requestTicker(currency: String): CoinOneTicker
+}
\ No newline at end of file
diff --git a/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/source/coinone/CoinOneRepositoryImpl.kt b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/source/coinone/CoinOneRepositoryImpl.kt
new file mode 100644
index 0000000..a052810
--- /dev/null
+++ b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/source/coinone/CoinOneRepositoryImpl.kt
@@ -0,0 +1,13 @@
+package sample.nackun.com.studyfirst.data.source.upbit
+
+import sample.nackun.com.studyfirst.data.model.CoinOneTicker
+
+class CoinOneRepositoryImpl(
+ private val remoteDataSource: CoinOneDataSource
+) : CoinOneRepository {
+ override suspend fun requestTicker(currency: String): CoinOneTicker =
+ remoteDataSource.requestTicker(currency)
+
+ override suspend fun requestAllTicker() =
+ remoteDataSource.requestAllTicker()
+}
\ No newline at end of file
diff --git a/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/source/coinone/remote/CoinOneRemoteDataSource.kt b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/source/coinone/remote/CoinOneRemoteDataSource.kt
new file mode 100644
index 0000000..160f7b2
--- /dev/null
+++ b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/source/coinone/remote/CoinOneRemoteDataSource.kt
@@ -0,0 +1,15 @@
+package sample.nackun.com.studyfirst.data.source.coinone.remote
+
+import sample.nackun.com.studyfirst.data.source.upbit.CoinOneDataSource
+import sample.nackun.com.studyfirst.data.api.CoinOneApi
+import sample.nackun.com.studyfirst.data.model.CoinOneTicker
+
+class CoinOneRemoteDataSource(
+ private val retrofitService: CoinOneApi
+) : CoinOneDataSource {
+ override suspend fun requestTicker(currency: String): CoinOneTicker =
+ retrofitService.requestTicker(currency)
+
+ override suspend fun requestAllTicker() =
+ retrofitService.requestAllTicker()
+}
\ No newline at end of file
diff --git a/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/source/upbit/UpbitDataSource.kt b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/source/upbit/UpbitDataSource.kt
new file mode 100644
index 0000000..c1b7a2d
--- /dev/null
+++ b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/source/upbit/UpbitDataSource.kt
@@ -0,0 +1,9 @@
+package sample.nackun.com.studyfirst.data.source.upbit
+
+import sample.nackun.com.studyfirst.data.model.UpbitMarket
+import sample.nackun.com.studyfirst.data.model.UpbitTicker
+
+interface UpbitDataSource {
+ suspend fun requestMarket(): List
+ suspend fun requestTicker(markets: String): List
+}
\ No newline at end of file
diff --git a/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/source/upbit/UpbitRepository.kt b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/source/upbit/UpbitRepository.kt
new file mode 100644
index 0000000..4c74f12
--- /dev/null
+++ b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/source/upbit/UpbitRepository.kt
@@ -0,0 +1,9 @@
+package sample.nackun.com.studyfirst.data.source.upbit
+
+import sample.nackun.com.studyfirst.data.model.UpbitMarket
+import sample.nackun.com.studyfirst.data.model.UpbitTicker
+
+interface UpbitRepository {
+ suspend fun requestMarket(): List
+ suspend fun requestTicker(markets: String): List
+}
\ No newline at end of file
diff --git a/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/source/upbit/UpbitRepositoryImpl.kt b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/source/upbit/UpbitRepositoryImpl.kt
new file mode 100644
index 0000000..0985fd2
--- /dev/null
+++ b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/source/upbit/UpbitRepositoryImpl.kt
@@ -0,0 +1,11 @@
+package sample.nackun.com.studyfirst.data.source.upbit
+
+class UpbitRepositoryImpl(
+ private val remoteDataSource: UpbitDataSource
+) : UpbitRepository {
+ override suspend fun requestMarket() =
+ remoteDataSource.requestMarket()
+
+ override suspend fun requestTicker(markets: String) =
+ remoteDataSource.requestTicker(markets)
+}
\ No newline at end of file
diff --git a/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/source/upbit/remote/UpbitRemoteDataSource.kt b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/source/upbit/remote/UpbitRemoteDataSource.kt
new file mode 100644
index 0000000..07e0fc2
--- /dev/null
+++ b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/source/upbit/remote/UpbitRemoteDataSource.kt
@@ -0,0 +1,14 @@
+package sample.nackun.com.studyfirst.data.source.upbit.remote
+
+import sample.nackun.com.studyfirst.data.source.upbit.UpbitDataSource
+import sample.nackun.com.studyfirst.data.api.UpbitApi
+
+class UpbitRemoteDataSource(
+ private val retrofitService: UpbitApi
+) : UpbitDataSource {
+ override suspend fun requestMarket() =
+ retrofitService.requestMarket()
+
+ override suspend fun requestTicker(markets: String) =
+ retrofitService.requestTicker(markets)
+}
\ No newline at end of file
diff --git a/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/util/TickerExt.kt b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/util/TickerExt.kt
new file mode 100644
index 0000000..e4f7907
--- /dev/null
+++ b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/data/util/TickerExt.kt
@@ -0,0 +1,39 @@
+package sample.nackun.com.studyfirst.data.util
+
+import android.annotation.SuppressLint
+import sample.nackun.com.studyfirst.R
+import sample.nackun.com.studyfirst.domain.entity.Ticker
+import sample.nackun.com.studyfirst.data.model.BithumbTicker
+import sample.nackun.com.studyfirst.data.model.CoinOneTicker
+import sample.nackun.com.studyfirst.data.model.UpbitTicker
+
+fun UpbitTicker.toTicker(): Ticker =
+ Ticker(
+ this.accTradePrice24h,
+ this.changePrice,
+ this.market.split("-")[1],
+ this.prevClosingPrice,
+ this.tradePrice,
+ R.drawable.upbit_img
+ )
+
+fun BithumbTicker.toTicker(): Ticker =
+ Ticker(
+ this.accTradeValue24H,
+ this.fluctate24H,
+ this.getMarket(),
+ this.prevClosingPrice,
+ this.closingPrice,
+ R.drawable.bithumb_img
+ )
+
+@SuppressLint("DefaultLocale")
+fun CoinOneTicker.toTicker(): Ticker =
+ Ticker(
+ this.volume.toDouble() * this.last.toDouble(),
+ this.first.toDouble() - this.last.toDouble(),
+ this.currency.toUpperCase(),
+ this.yesterdayLast.toDouble(),
+ this.last.toDouble(),
+ R.drawable.coinone_img
+ )
\ No newline at end of file
diff --git a/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/domain/di/UseCaseModule.kt b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/domain/di/UseCaseModule.kt
new file mode 100644
index 0000000..89b44f1
--- /dev/null
+++ b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/domain/di/UseCaseModule.kt
@@ -0,0 +1,30 @@
+package sample.nackun.com.studyfirst.domain.di
+
+import org.koin.dsl.module
+import sample.nackun.com.studyfirst.domain.usecase.*
+
+val useCaseModule = module {
+ single {
+ GetUpbitMarketUseCase(get())
+ }
+
+ single {
+ GetUpbitTickersUseCase(get())
+ }
+
+ single {
+ GetBithumbTickersUseCase(get())
+ }
+
+ single {
+ GetCoinOneTickersUseCase(get())
+ }
+
+ single {
+ GetBithumbTickerUseCase(get())
+ }
+
+ single {
+ GetCoinOneTickerUseCase(get())
+ }
+}
\ No newline at end of file
diff --git a/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/domain/entity/Ticker.kt b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/domain/entity/Ticker.kt
new file mode 100644
index 0000000..256feb2
--- /dev/null
+++ b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/domain/entity/Ticker.kt
@@ -0,0 +1,10 @@
+package sample.nackun.com.studyfirst.domain.entity
+
+data class Ticker(
+ val accTradePrice24h: Double,
+ val changePrice: Double,
+ val market: String,
+ val prevClosingPrice: Double,
+ val tradePrice: Double,
+ val exchangeImg: Int
+)
\ No newline at end of file
diff --git a/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/domain/usecase/GetBithumbTickerUseCase.kt b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/domain/usecase/GetBithumbTickerUseCase.kt
new file mode 100644
index 0000000..ff55622
--- /dev/null
+++ b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/domain/usecase/GetBithumbTickerUseCase.kt
@@ -0,0 +1,17 @@
+package sample.nackun.com.studyfirst.domain.usecase
+
+import com.google.gson.Gson
+import sample.nackun.com.studyfirst.data.source.bithumb.BithumbRepository
+import sample.nackun.com.studyfirst.domain.entity.Ticker
+import sample.nackun.com.studyfirst.data.util.toTicker
+import sample.nackun.com.studyfirst.data.model.BithumbTicker
+
+class GetBithumbTickerUseCase(private val repository: BithumbRepository) {
+ suspend operator fun invoke(currency: String): Ticker =
+ repository.requestTicker(currency).let {
+ val gson = Gson()
+ gson.fromJson(it.bithumbData.toString(), BithumbTicker::class.java).apply {
+ setMarket(currency)
+ }.toTicker()
+ }
+}
\ No newline at end of file
diff --git a/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/domain/usecase/GetBithumbTickersUseCase.kt b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/domain/usecase/GetBithumbTickersUseCase.kt
new file mode 100644
index 0000000..d6adb90
--- /dev/null
+++ b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/domain/usecase/GetBithumbTickersUseCase.kt
@@ -0,0 +1,23 @@
+package sample.nackun.com.studyfirst.domain.usecase
+
+import com.google.gson.Gson
+import sample.nackun.com.studyfirst.data.source.bithumb.BithumbRepository
+import sample.nackun.com.studyfirst.domain.entity.Ticker
+import sample.nackun.com.studyfirst.data.util.toTicker
+import sample.nackun.com.studyfirst.data.model.BithumbTicker
+
+class GetBithumbTickersUseCase(private val repository: BithumbRepository) {
+ suspend operator fun invoke(): List =
+ repository.requestAllTicker().let {
+ it.bithumbData.filterKeys {
+ !it.equals("date")
+ }.map { bithumbTicker ->
+ val gson = Gson()
+ gson.fromJson(bithumbTicker.value.toString(), BithumbTicker::class.java).apply {
+ setMarket(bithumbTicker.key)
+ }
+ }.map { bithumbTicker ->
+ bithumbTicker.toTicker()
+ }
+ }
+}
\ No newline at end of file
diff --git a/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/domain/usecase/GetCoinOneTickerUseCase.kt b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/domain/usecase/GetCoinOneTickerUseCase.kt
new file mode 100644
index 0000000..c0eadcb
--- /dev/null
+++ b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/domain/usecase/GetCoinOneTickerUseCase.kt
@@ -0,0 +1,10 @@
+package sample.nackun.com.studyfirst.domain.usecase
+
+import sample.nackun.com.studyfirst.data.source.upbit.CoinOneRepository
+import sample.nackun.com.studyfirst.domain.entity.Ticker
+import sample.nackun.com.studyfirst.data.util.toTicker
+
+class GetCoinOneTickerUseCase(private val repository: CoinOneRepository) {
+ suspend operator fun invoke(currency: String): Ticker =
+ repository.requestTicker(currency).toTicker()
+}
\ No newline at end of file
diff --git a/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/domain/usecase/GetCoinOneTickersUseCase.kt b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/domain/usecase/GetCoinOneTickersUseCase.kt
new file mode 100644
index 0000000..55c0ad2
--- /dev/null
+++ b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/domain/usecase/GetCoinOneTickersUseCase.kt
@@ -0,0 +1,19 @@
+package sample.nackun.com.studyfirst.domain.usecase
+
+import com.google.gson.Gson
+import sample.nackun.com.studyfirst.data.source.upbit.CoinOneRepository
+import sample.nackun.com.studyfirst.domain.entity.Ticker
+import sample.nackun.com.studyfirst.data.util.toTicker
+import sample.nackun.com.studyfirst.data.model.CoinOneTicker
+
+class GetCoinOneTickersUseCase(private val repository: CoinOneRepository) {
+ suspend operator fun invoke(): List =
+ repository.requestAllTicker().filter {
+ !(it.key == "result" || it.key == "errorCode" || it.key == "timestamp")
+ }.map {
+ val gson = Gson()
+ gson.fromJson(it.value.toString(), CoinOneTicker::class.java)
+ }.map {
+ it.toTicker()
+ }
+}
\ No newline at end of file
diff --git a/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/domain/usecase/GetUpbitMarketUseCase.kt b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/domain/usecase/GetUpbitMarketUseCase.kt
new file mode 100644
index 0000000..244b6bc
--- /dev/null
+++ b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/domain/usecase/GetUpbitMarketUseCase.kt
@@ -0,0 +1,8 @@
+package sample.nackun.com.studyfirst.domain.usecase
+
+import sample.nackun.com.studyfirst.data.source.upbit.UpbitRepository
+import sample.nackun.com.studyfirst.data.model.UpbitMarket
+
+class GetUpbitMarketUseCase(private val repository: UpbitRepository) {
+ suspend operator fun invoke(): List = repository.requestMarket()
+}
\ No newline at end of file
diff --git a/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/domain/usecase/GetUpbitTickersUseCase.kt b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/domain/usecase/GetUpbitTickersUseCase.kt
new file mode 100644
index 0000000..de418fc
--- /dev/null
+++ b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/domain/usecase/GetUpbitTickersUseCase.kt
@@ -0,0 +1,10 @@
+package sample.nackun.com.studyfirst.domain.usecase
+
+import sample.nackun.com.studyfirst.data.source.upbit.UpbitRepository
+import sample.nackun.com.studyfirst.domain.entity.Ticker
+import sample.nackun.com.studyfirst.data.util.toTicker
+
+class GetUpbitTickersUseCase(private val repository: UpbitRepository) {
+ suspend operator fun invoke(market: String): List =
+ repository.requestTicker(market).map { it.toTicker() }
+}
\ No newline at end of file
diff --git a/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/presentation/base/BaseActivity.kt b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/presentation/base/BaseActivity.kt
new file mode 100644
index 0000000..ef1b5d0
--- /dev/null
+++ b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/presentation/base/BaseActivity.kt
@@ -0,0 +1,16 @@
+package sample.nackun.com.studyfirst.presentation.base
+
+import android.os.Bundle
+import androidx.annotation.LayoutRes
+import androidx.appcompat.app.AppCompatActivity
+import androidx.databinding.ViewDataBinding
+
+abstract class BaseActivity(
+ @LayoutRes private val layoutRes: Int
+) : AppCompatActivity() {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(layoutRes)
+ }
+}
\ No newline at end of file
diff --git a/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/presentation/base/BaseFragment.kt b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/presentation/base/BaseFragment.kt
new file mode 100644
index 0000000..b746008
--- /dev/null
+++ b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/presentation/base/BaseFragment.kt
@@ -0,0 +1,34 @@
+package sample.nackun.com.studyfirst.presentation.base
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.Toast
+import androidx.annotation.LayoutRes
+import androidx.databinding.DataBindingUtil
+import androidx.databinding.ViewDataBinding
+import androidx.fragment.app.Fragment
+import androidx.lifecycle.ViewModel
+
+abstract class BaseFragment(
+ @LayoutRes private val layoutRes: Int
+) : Fragment() {
+
+ protected lateinit var binding: B
+
+ abstract val vm: VM
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? {
+ binding = DataBindingUtil.inflate(inflater, layoutRes, container, false)
+ binding.lifecycleOwner = this
+ return binding.root
+ }
+
+ fun showToast(msg: String?) =
+ Toast.makeText(activity, msg, Toast.LENGTH_SHORT).show()
+}
\ No newline at end of file
diff --git a/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/presentation/base/BaseRecyclerView.kt b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/presentation/base/BaseRecyclerView.kt
new file mode 100644
index 0000000..8c65778
--- /dev/null
+++ b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/presentation/base/BaseRecyclerView.kt
@@ -0,0 +1,56 @@
+package sample.nackun.com.studyfirst.presentation.base
+
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.annotation.LayoutRes
+import androidx.databinding.DataBindingUtil
+import androidx.databinding.ViewDataBinding
+import androidx.recyclerview.widget.RecyclerView
+
+class BaseRecyclerView {
+
+ abstract class BaseAdapter- (
+ @LayoutRes private val layoutRes: Int,
+ private val bindingVariabledId: Int
+ ) : RecyclerView.Adapter>() {
+
+ protected val items = mutableListOf
- ()
+
+ fun setItems(items: List
- ?) {
+ this.items.run {
+ items?.let {
+ clear()
+ addAll(it)
+ }
+ }
+ }
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
+ object : BaseViewHolder(
+ layoutRes = layoutRes,
+ parent = parent,
+ bindingVariabledId = bindingVariabledId
+ ) {}
+
+ override fun getItemCount() = items.size
+
+ override fun onBindViewHolder(baseViewHolder: BaseViewHolder, position: Int) =
+ items[position].let(baseViewHolder::bind)
+ }
+
+ abstract class BaseViewHolder(
+ @LayoutRes layoutRes: Int,
+ parent: ViewGroup?,
+ private val bindingVariabledId: Int
+ ) : RecyclerView.ViewHolder(
+ LayoutInflater.from(parent?.context)
+ .inflate(layoutRes, parent, false)
+ ) {
+ private val binding: B = DataBindingUtil.bind(itemView)!!
+
+ fun bind(item: Any?) {
+ binding.setVariable(bindingVariabledId, item)
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/presentation/base/BaseViewModel.kt b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/presentation/base/BaseViewModel.kt
new file mode 100644
index 0000000..448b8e8
--- /dev/null
+++ b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/presentation/base/BaseViewModel.kt
@@ -0,0 +1,21 @@
+package sample.nackun.com.studyfirst.presentation.base
+
+import androidx.lifecycle.ViewModel
+import io.reactivex.disposables.CompositeDisposable
+import io.reactivex.disposables.Disposable
+
+abstract class BaseViewModel : ViewModel() {
+
+ private val compositeDisposable = CompositeDisposable()
+
+ fun addDisposable(disposable: Disposable) =
+ compositeDisposable.add(disposable)
+
+ fun removeDisposable(disposable: CompositeDisposable) =
+ compositeDisposable.remove(disposable)
+
+ override fun onCleared() {
+ compositeDisposable.clear()
+ super.onCleared()
+ }
+}
\ No newline at end of file
diff --git a/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/presentation/detail/DetailActivity.kt b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/presentation/detail/DetailActivity.kt
new file mode 100644
index 0000000..d3a6800
--- /dev/null
+++ b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/presentation/detail/DetailActivity.kt
@@ -0,0 +1,7 @@
+package sample.nackun.com.studyfirst.presentation.detail
+
+import androidx.databinding.ViewDataBinding
+import sample.nackun.com.studyfirst.R
+import sample.nackun.com.studyfirst.presentation.base.BaseActivity
+
+class DetailActivity : BaseActivity(R.layout.activity_detail)
\ No newline at end of file
diff --git a/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/presentation/detail/DetailFragment.kt b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/presentation/detail/DetailFragment.kt
new file mode 100644
index 0000000..df0be87
--- /dev/null
+++ b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/presentation/detail/DetailFragment.kt
@@ -0,0 +1,45 @@
+package sample.nackun.com.studyfirst.presentation.detail
+
+import android.os.Bundle
+import kotlinx.android.synthetic.main.detail_fragment.*
+import org.koin.androidx.viewmodel.ext.android.viewModel
+import org.koin.core.parameter.parametersOf
+import sample.nackun.com.studyfirst.BR
+import sample.nackun.com.studyfirst.R
+import sample.nackun.com.studyfirst.presentation.base.BaseFragment
+import sample.nackun.com.studyfirst.presentation.base.BaseRecyclerView
+import sample.nackun.com.studyfirst.databinding.DetailFragmentBinding
+import sample.nackun.com.studyfirst.databinding.TickerItemBinding
+
+class DetailFragment : BaseFragment(
+ R.layout.detail_fragment
+) {
+ private val detailAdapter =
+ object :
+ BaseRecyclerView.BaseAdapter
>, TickerItemBinding>(
+ R.layout.ticker_item,
+ BR.tickerItem
+ ) {}
+
+ override val vm: DetailViewModel by viewModel {
+ parametersOf(activity!!.intent.getStringExtra("currency"))
+ }
+
+ override fun onActivityCreated(savedInstanceState: Bundle?) {
+ super.onActivityCreated(savedInstanceState)
+ initViewModel()
+ setAdapter()
+ setTickers()
+ }
+
+ private fun initViewModel() {
+ binding.detailViewModel = vm
+ }
+
+ private fun setAdapter() {
+ detail_recyclerView.adapter = detailAdapter
+ }
+
+ private fun setTickers() =
+ vm.showTickers()
+}
\ No newline at end of file
diff --git a/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/presentation/detail/DetailViewModel.kt b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/presentation/detail/DetailViewModel.kt
new file mode 100644
index 0000000..1c53e78
--- /dev/null
+++ b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/presentation/detail/DetailViewModel.kt
@@ -0,0 +1,76 @@
+package sample.nackun.com.studyfirst.presentation.detail
+
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.viewModelScope
+import kotlinx.coroutines.async
+import kotlinx.coroutines.launch
+import sample.nackun.com.studyfirst.domain.usecase.GetBithumbTickerUseCase
+import sample.nackun.com.studyfirst.domain.usecase.GetCoinOneTickerUseCase
+import sample.nackun.com.studyfirst.domain.usecase.GetUpbitTickersUseCase
+import sample.nackun.com.studyfirst.presentation.base.BaseViewModel
+import sample.nackun.com.studyfirst.presentation.model.Ticker
+import sample.nackun.com.studyfirst.presentation.util.TickerFormatter
+import sample.nackun.com.studyfirst.presentation.util.toPresentation
+
+class DetailViewModel(
+ private val tickerName: String,
+ private val getUpbitTickersUseCase: GetUpbitTickersUseCase,
+ private val getBithumbTickerUseCase: GetBithumbTickerUseCase,
+ private val getCoinOneTickerUseCase: GetCoinOneTickerUseCase
+) : BaseViewModel() {
+ private val _tickers = MutableLiveData>>()
+ val tickers: LiveData>> get() = _tickers
+ private val _errMsg = MutableLiveData()
+ val errMsg: LiveData get() = _errMsg
+
+ init {
+ _tickers.value = mutableListOf()
+ }
+
+ private fun onError(t: Throwable) {
+ _errMsg.value = t
+ }
+
+ private fun onTickersLoaded(tickers: List) {
+ _tickers.value = TickerFormatter.convertTo(tickers)
+ }
+
+ fun showTickers() {
+ viewModelScope.launch {
+ val tickers: MutableList = mutableListOf()
+
+ async {
+ try {
+ getUpbitTickersUseCase("KRW-" + tickerName)
+ } catch (cause: Throwable) {
+ return@async null
+ }
+ }.await()?.let {
+ tickers.add(it.last())
+ }
+
+ async {
+ try {
+ getBithumbTickerUseCase(tickerName)
+ } catch (cause: Throwable) {
+ return@async null
+ }
+ }.await()?.let {
+ tickers.add(it)
+ }
+
+ async {
+ try {
+ getCoinOneTickerUseCase(tickerName)
+ } catch (cause: Throwable) {
+ return@async null
+ }
+ }.await()?.let {
+ tickers.add(it)
+ }
+
+ onTickersLoaded(tickers.toPresentation())
+ }
+ }
+}
\ No newline at end of file
diff --git a/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/presentation/di/ViewModelModule.kt b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/presentation/di/ViewModelModule.kt
new file mode 100644
index 0000000..f0b1118
--- /dev/null
+++ b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/presentation/di/ViewModelModule.kt
@@ -0,0 +1,13 @@
+package sample.nackun.com.studyfirst.presentation.di
+
+import org.koin.androidx.viewmodel.dsl.viewModel
+import org.koin.dsl.module
+import sample.nackun.com.studyfirst.presentation.detail.DetailViewModel
+import sample.nackun.com.studyfirst.presentation.ticker.TickerViewModel
+
+val viewModelModule = module {
+ viewModel { TickerViewModel(get(), get(), get(), get()) }
+ viewModel { (currency: String) ->
+ DetailViewModel(currency, get(), get(), get())
+ }
+}
\ No newline at end of file
diff --git a/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/presentation/model/Ticker.kt b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/presentation/model/Ticker.kt
new file mode 100644
index 0000000..c6f21da
--- /dev/null
+++ b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/presentation/model/Ticker.kt
@@ -0,0 +1,10 @@
+package sample.nackun.com.studyfirst.presentation.model
+
+data class Ticker(
+ val accTradePrice24h: Double,
+ val changePrice: Double,
+ val market: String,
+ val prevClosingPrice: Double,
+ val tradePrice: Double,
+ val exchangeImg: Int
+)
\ No newline at end of file
diff --git a/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/presentation/ticker/TickerActivity.kt b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/presentation/ticker/TickerActivity.kt
new file mode 100644
index 0000000..0e53fce
--- /dev/null
+++ b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/presentation/ticker/TickerActivity.kt
@@ -0,0 +1,7 @@
+package sample.nackun.com.studyfirst.presentation.ticker
+
+import androidx.databinding.ViewDataBinding
+import sample.nackun.com.studyfirst.R
+import sample.nackun.com.studyfirst.presentation.base.BaseActivity
+
+class TickerActivity : BaseActivity(R.layout.activity_ticker)
\ No newline at end of file
diff --git a/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/presentation/ticker/TickerFragment.kt b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/presentation/ticker/TickerFragment.kt
new file mode 100644
index 0000000..2aedddf
--- /dev/null
+++ b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/presentation/ticker/TickerFragment.kt
@@ -0,0 +1,63 @@
+package sample.nackun.com.studyfirst.presentation.ticker
+
+import android.annotation.SuppressLint
+import android.content.Intent
+import android.os.Bundle
+import androidx.lifecycle.Observer
+import kotlinx.android.synthetic.main.ticker_fragment.*
+import org.koin.androidx.viewmodel.ext.android.viewModel
+import sample.nackun.com.studyfirst.BR
+import sample.nackun.com.studyfirst.R
+import sample.nackun.com.studyfirst.presentation.base.BaseFragment
+import sample.nackun.com.studyfirst.databinding.TickerFragmentBinding
+import sample.nackun.com.studyfirst.databinding.TickerItemBinding
+import sample.nackun.com.studyfirst.presentation.detail.DetailActivity
+import sample.nackun.com.studyfirst.presentation.util.ClickAdapter
+
+class TickerFragment : BaseFragment(
+ R.layout.ticker_fragment
+) {
+ private val firstMarketName = "KRW"
+ private val tickerAdapter =
+ object :
+ ClickAdapter>, TickerItemBinding>(
+ R.layout.ticker_item,
+ BR.tickerItem
+ ) {}
+
+ override val vm: TickerViewModel by viewModel()
+
+ override fun onActivityCreated(savedInstanceState: Bundle?) {
+ super.onActivityCreated(savedInstanceState)
+ initViewModel()
+ setAdapter()
+ setFirstTickers()
+ setOnClick()
+ }
+
+ private fun initViewModel() {
+ binding.setVariable(BR.vm, vm)
+
+ val errMsgObserver = Observer {
+ showToast(it.message)
+ }
+
+ vm.errMsg.observe(viewLifecycleOwner, errMsgObserver)
+ }
+
+ private fun setAdapter() {
+ tickerRecyclerView.adapter = tickerAdapter
+ }
+
+ private fun setFirstTickers() =
+ vm.showTickers(firstMarketName)
+
+ @SuppressLint("CheckResult")
+ private fun setOnClick() {
+ tickerAdapter.getOnItemClickObservable().subscribe {
+ val detailIntent = Intent(context, DetailActivity::class.java)
+ detailIntent.putExtra("currency", vm.tickers.value!!.get(it).get("tickerName"))
+ startActivity(detailIntent)
+ }
+ }
+}
\ No newline at end of file
diff --git a/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/presentation/ticker/TickerItemExt.kt b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/presentation/ticker/TickerItemExt.kt
new file mode 100644
index 0000000..3eee56d
--- /dev/null
+++ b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/presentation/ticker/TickerItemExt.kt
@@ -0,0 +1,9 @@
+package sample.nackun.com.studyfirst.presentation.ticker
+
+import android.widget.ImageView
+import androidx.databinding.BindingAdapter
+
+@BindingAdapter("setImg")
+fun ImageView.setImg(src: Int) {
+ this.setImageResource(src)
+}
\ No newline at end of file
diff --git a/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/presentation/ticker/TickerRecyclerViewExt.kt b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/presentation/ticker/TickerRecyclerViewExt.kt
new file mode 100644
index 0000000..737f27a
--- /dev/null
+++ b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/presentation/ticker/TickerRecyclerViewExt.kt
@@ -0,0 +1,14 @@
+package sample.nackun.com.studyfirst.presentation.ticker
+
+import androidx.databinding.BindingAdapter
+import androidx.recyclerview.widget.RecyclerView
+import sample.nackun.com.studyfirst.presentation.base.BaseRecyclerView
+
+@Suppress("UNCHECKED_CAST")
+@BindingAdapter("setItems")
+fun RecyclerView.setItems(items: List