diff --git a/app/.gitignore b/app/.gitignore
new file mode 100644
index 0000000..796b96d
--- /dev/null
+++ b/app/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/app/build.gradle b/app/build.gradle
new file mode 100644
index 0000000..8f6b331
--- /dev/null
+++ b/app/build.gradle
@@ -0,0 +1,76 @@
+apply plugin: 'com.android.application'
+
+apply plugin: 'kotlin-android'
+
+apply plugin: 'kotlin-android-extensions'
+
+apply plugin: 'kotlin-kapt'
+
+android {
+ compileSdkVersion 29
+ buildToolsVersion "29.0.2"
+ defaultConfig {
+ applicationId "com.example.sunday"
+ minSdkVersion 28
+ targetSdkVersion 29
+ versionCode 1
+ versionName "1.0"
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ }
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+
+ dataBinding{
+ enabled = true
+ }
+}
+
+dependencies {
+ implementation fileTree(dir: 'libs', include: ['*.jar'])
+ implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
+ implementation 'androidx.appcompat:appcompat:1.1.0'
+ implementation 'androidx.core:core-ktx:1.1.0'
+ implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
+ testImplementation 'junit:junit:4.12'
+ androidTestImplementation 'androidx.test.ext:junit:1.1.1'
+ androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
+
+ // material
+ implementation "com.google.android.material:material:1.0.0"
+
+ // ViewModel and LiveData
+ implementation "androidx.lifecycle:lifecycle-extensions:2.2.0-rc01"
+ implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0-rc01'
+
+
+ //Retrofit2
+ implementation 'com.squareup.retrofit2:retrofit:2.6.0'
+ implementation 'com.squareup.retrofit2:converter-gson:2.6.0'
+ implementation "com.squareup.retrofit2:adapter-rxjava2:2.6.0"
+
+ //Glide
+ implementation 'com.github.bumptech.glide:glide:4.10.0'
+ annotationProcessor 'com.github.bumptech.glide:compiler:4.10.0'
+
+ //Browser Helper
+ implementation 'com.google.androidbrowserhelper:androidbrowserhelper:0.1.0-alpha1'
+
+ // RxJava2
+ implementation "io.reactivex.rxjava2:rxandroid:2.1.1"
+ implementation "io.reactivex.rxjava2:rxjava:2.2.15"
+
+ //Koin lib
+ implementation 'org.koin:koin-androidx-scope:2.0.1'
+ implementation 'org.koin:koin-androidx-viewmodel:2.0.1'
+ implementation 'org.koin:koin-androidx-ext:2.0.1'
+
+ // Coroutines
+ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.0'
+ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.0'
+
+
+}
diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro
new file mode 100644
index 0000000..f1b4245
--- /dev/null
+++ b/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/app/src/androidTest/java/com/example/sunday/ExampleInstrumentedTest.kt b/app/src/androidTest/java/com/example/sunday/ExampleInstrumentedTest.kt
new file mode 100644
index 0000000..54ae364
--- /dev/null
+++ b/app/src/androidTest/java/com/example/sunday/ExampleInstrumentedTest.kt
@@ -0,0 +1,22 @@
+package com.example.sunday
+
+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().targetContext
+ assertEquals("com.example.sunday", appContext.packageName)
+ }
+}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..0ec1201
--- /dev/null
+++ b/app/src/main/AndroidManifest.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/example/sunday/CoinApplication.kt b/app/src/main/java/com/example/sunday/CoinApplication.kt
new file mode 100644
index 0000000..3e33e8b
--- /dev/null
+++ b/app/src/main/java/com/example/sunday/CoinApplication.kt
@@ -0,0 +1,21 @@
+package com.example.sunday
+
+
+import android.app.Application
+import com.example.sunday.di.networkModuelUpbit
+import com.example.sunday.di.viewModelModule
+import org.koin.android.ext.koin.androidContext
+import org.koin.core.context.startKoin
+
+
+class CoinApplication : Application() {
+ private val moduleList = listOf(viewModelModule, networkModuelUpbit)
+
+ override fun onCreate() {
+ super.onCreate()
+ startKoin {
+ androidContext(this@CoinApplication)
+ modules(moduleList)
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/sunday/base/BaseActivity.kt b/app/src/main/java/com/example/sunday/base/BaseActivity.kt
new file mode 100644
index 0000000..6233488
--- /dev/null
+++ b/app/src/main/java/com/example/sunday/base/BaseActivity.kt
@@ -0,0 +1,34 @@
+package com.example.sunday.base
+
+import android.content.pm.ActivityInfo
+import android.os.Bundle
+import android.widget.Toast
+import androidx.annotation.LayoutRes
+import androidx.appcompat.app.AppCompatActivity
+import androidx.databinding.DataBindingUtil
+import androidx.databinding.ViewDataBinding
+
+abstract class BaseActivity(@LayoutRes private val layoutId: Int) :
+ AppCompatActivity() {
+
+ protected lateinit var binding: B
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ binding = DataBindingUtil.setContentView(this, layoutId)
+ binding.lifecycleOwner = this
+
+ setOrientationToPortrait()
+ }
+
+ protected fun showToastMessage(msg: String?) {
+ if (!msg.isNullOrEmpty()) {
+ Toast.makeText(this, msg, Toast.LENGTH_SHORT).show()
+ }
+ }
+
+ private fun setOrientationToPortrait() {
+ requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/sunday/base/BaseViewHolder.kt b/app/src/main/java/com/example/sunday/base/BaseViewHolder.kt
new file mode 100644
index 0000000..d199f53
--- /dev/null
+++ b/app/src/main/java/com/example/sunday/base/BaseViewHolder.kt
@@ -0,0 +1,16 @@
+package com.example.sunday.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
+
+abstract class BaseViewHolder(@LayoutRes private val layoutId: Int, parent: ViewGroup) :
+ RecyclerView.ViewHolder(
+ LayoutInflater.from(parent.context).inflate(layoutId, parent, false)
+ ) {
+
+ protected val binding: B = DataBindingUtil.bind(itemView)!!
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/sunday/data/enums/BaseCurrency.kt b/app/src/main/java/com/example/sunday/data/enums/BaseCurrency.kt
new file mode 100644
index 0000000..0421216
--- /dev/null
+++ b/app/src/main/java/com/example/sunday/data/enums/BaseCurrency.kt
@@ -0,0 +1,28 @@
+package com.example.sunday.data.enums
+
+enum class BaseCurrency {
+ KRW,
+ BTC,
+ ETH,
+ USDT,
+ BNB,
+ USD,
+ EUR,
+ GBP,
+ JPY,
+ EOS,
+ HT,
+ BCH,
+ EURS,
+ DAI,
+ TUSD,
+ QC,
+ ZB,
+ PAX,
+ LBCN,
+ QTUM,
+ ELA,
+ DAX,
+ BIX,
+ GUSD
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/sunday/data/enums/Exchange.kt b/app/src/main/java/com/example/sunday/data/enums/Exchange.kt
new file mode 100644
index 0000000..201cd97
--- /dev/null
+++ b/app/src/main/java/com/example/sunday/data/enums/Exchange.kt
@@ -0,0 +1,7 @@
+package com.example.sunday.data.enums
+
+enum class Exchange(val exchangeName: String) {
+ UPBIT("Upbit"),
+ BITHUMB("Bithumb"),
+ COINONE("Coinone")
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/sunday/data/model/ExchangeTicker.kt b/app/src/main/java/com/example/sunday/data/model/ExchangeTicker.kt
new file mode 100644
index 0000000..e456ffd
--- /dev/null
+++ b/app/src/main/java/com/example/sunday/data/model/ExchangeTicker.kt
@@ -0,0 +1,12 @@
+package com.example.sunday.data.model
+
+class ExchangeTicker (
+ val exchangeName: String,
+ ticker: Ticker)
+ : Ticker(currency = ticker.currency,
+ baseCurrency = ticker.baseCurrency,
+ last = ticker.last,
+ high = ticker.high,
+ low = ticker.low,
+ volume = ticker.volume,
+ diff = ticker.diff)
\ No newline at end of file
diff --git a/app/src/main/java/com/example/sunday/data/model/Ticker.kt b/app/src/main/java/com/example/sunday/data/model/Ticker.kt
new file mode 100644
index 0000000..b7a406b
--- /dev/null
+++ b/app/src/main/java/com/example/sunday/data/model/Ticker.kt
@@ -0,0 +1,14 @@
+package com.example.sunday.data.model
+
+open class Ticker(
+ var currency: String? = "",
+ var baseCurrency: String? = "",
+ var last: Double?,
+ var high: Double?,
+ var low: Double?,
+ var volume: Double?,
+ var diff: Double? = null) : TickerProvider{
+
+ override fun toTicker(): Ticker = this
+ override fun toExchangeTicker(exchangeName: String): ExchangeTicker = ExchangeTicker(exchangeName, this)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/sunday/data/model/TickerProvider.kt b/app/src/main/java/com/example/sunday/data/model/TickerProvider.kt
new file mode 100644
index 0000000..3155f1e
--- /dev/null
+++ b/app/src/main/java/com/example/sunday/data/model/TickerProvider.kt
@@ -0,0 +1,6 @@
+package com.example.sunday.data.model
+
+interface TickerProvider {
+ fun toTicker(): Ticker
+ fun toExchangeTicker(exchangeName: String = "empty") : ExchangeTicker
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/sunday/data/repository/ticker/BithumbRepository.kt b/app/src/main/java/com/example/sunday/data/repository/ticker/BithumbRepository.kt
new file mode 100644
index 0000000..52f45f3
--- /dev/null
+++ b/app/src/main/java/com/example/sunday/data/repository/ticker/BithumbRepository.kt
@@ -0,0 +1,9 @@
+package com.example.sunday.data.repository.ticker
+
+import com.example.sunday.data.soruce.remote.RemoteTickerDataSource
+
+class BithumbRepository(private val remoteTickerDataSource: RemoteTickerDataSource) : TickerRepository {
+ override suspend fun getAllTicker():Any = remoteTickerDataSource.getAllTicker()
+ override suspend fun getTicker(currency: String) = remoteTickerDataSource.getTicker(currency)
+ override suspend fun getExchangeTicker(currency: String) = remoteTickerDataSource.getExchangeTicker(currency)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/sunday/data/repository/ticker/CoinoneRepository.kt b/app/src/main/java/com/example/sunday/data/repository/ticker/CoinoneRepository.kt
new file mode 100644
index 0000000..3c88879
--- /dev/null
+++ b/app/src/main/java/com/example/sunday/data/repository/ticker/CoinoneRepository.kt
@@ -0,0 +1,9 @@
+package com.example.sunday.data.repository.ticker
+
+import com.example.sunday.data.soruce.remote.RemoteTickerDataSource
+
+class CoinoneRepository(private val remoteTickerDataSource: RemoteTickerDataSource) : TickerRepository {
+ override suspend fun getAllTicker() = remoteTickerDataSource.getAllTicker()
+ override suspend fun getTicker(currency: String) = remoteTickerDataSource.getTicker(currency)
+ override suspend fun getExchangeTicker(currency: String) = remoteTickerDataSource.getExchangeTicker(currency)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/sunday/data/repository/ticker/TickerRepository.kt b/app/src/main/java/com/example/sunday/data/repository/ticker/TickerRepository.kt
new file mode 100644
index 0000000..e3bc852
--- /dev/null
+++ b/app/src/main/java/com/example/sunday/data/repository/ticker/TickerRepository.kt
@@ -0,0 +1,7 @@
+package com.example.sunday.data.repository.ticker
+
+interface TickerRepository {
+ suspend fun getAllTicker():Any
+ suspend fun getTicker(currency: String):Any
+ suspend fun getExchangeTicker(currency: String):Any
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/sunday/data/repository/ticker/UpbitRepository.kt b/app/src/main/java/com/example/sunday/data/repository/ticker/UpbitRepository.kt
new file mode 100644
index 0000000..f54b9b1
--- /dev/null
+++ b/app/src/main/java/com/example/sunday/data/repository/ticker/UpbitRepository.kt
@@ -0,0 +1,9 @@
+package com.example.sunday.data.repository.ticker
+
+import com.example.sunday.data.soruce.remote.RemoteTickerDataSource
+
+class UpbitRepository(private val remoteTickerDataSource: RemoteTickerDataSource) : TickerRepository {
+ override suspend fun getAllTicker(): Any = remoteTickerDataSource.getAllTicker()
+ override suspend fun getTicker(currency: String): Any = remoteTickerDataSource.getTicker(currency)
+ override suspend fun getExchangeTicker(currency: String): Any = remoteTickerDataSource.getExchangeTicker(currency)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/sunday/data/soruce/remote/RemoteBitumbDataSoruceImpl.kt b/app/src/main/java/com/example/sunday/data/soruce/remote/RemoteBitumbDataSoruceImpl.kt
new file mode 100644
index 0000000..ceec69b
--- /dev/null
+++ b/app/src/main/java/com/example/sunday/data/soruce/remote/RemoteBitumbDataSoruceImpl.kt
@@ -0,0 +1,9 @@
+package com.example.sunday.data.soruce.remote
+
+import com.example.sunday.network.api.BithumbApi
+
+class RemoteBitumbDataSoruceImpl(private val networkApi: BithumbApi) : RemoteTickerDataSource {
+ override suspend fun getAllTicker(): Any = networkApi.getTickerList()
+ override suspend fun getTicker(currency: String): Any = this
+ override suspend fun getExchangeTicker(currency: String):Any = networkApi.getExchangeTicker(currency)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/sunday/data/soruce/remote/RemoteCoinoneDataSourceImpl.kt b/app/src/main/java/com/example/sunday/data/soruce/remote/RemoteCoinoneDataSourceImpl.kt
new file mode 100644
index 0000000..8d6ae0c
--- /dev/null
+++ b/app/src/main/java/com/example/sunday/data/soruce/remote/RemoteCoinoneDataSourceImpl.kt
@@ -0,0 +1,9 @@
+package com.example.sunday.data.soruce.remote
+
+import com.example.sunday.network.api.CoinoneApi
+
+class RemoteCoinoneDataSourceImpl(private val networkApi: CoinoneApi) : RemoteTickerDataSource {
+ override suspend fun getAllTicker(): Any = networkApi.getAllTicker()
+ override suspend fun getTicker(currency: String): Any = networkApi.getTicker(currency)
+ override suspend fun getExchangeTicker(currency: String): Any = networkApi.getExchangeTicker(currency)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/sunday/data/soruce/remote/RemoteTickerDataSource.kt b/app/src/main/java/com/example/sunday/data/soruce/remote/RemoteTickerDataSource.kt
new file mode 100644
index 0000000..e037fe2
--- /dev/null
+++ b/app/src/main/java/com/example/sunday/data/soruce/remote/RemoteTickerDataSource.kt
@@ -0,0 +1,7 @@
+package com.example.sunday.data.soruce.remote
+
+interface RemoteTickerDataSource {
+ suspend fun getAllTicker():Any
+ suspend fun getTicker(currency: String):Any
+ suspend fun getExchangeTicker(currency: String):Any
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/sunday/data/soruce/remote/RemoteUpbitDataSourceImpl.kt b/app/src/main/java/com/example/sunday/data/soruce/remote/RemoteUpbitDataSourceImpl.kt
new file mode 100644
index 0000000..39b91b6
--- /dev/null
+++ b/app/src/main/java/com/example/sunday/data/soruce/remote/RemoteUpbitDataSourceImpl.kt
@@ -0,0 +1,9 @@
+package com.example.sunday.data.soruce.remote
+
+import com.example.sunday.network.api.UpbitApi
+
+class RemoteUpbitDataSourceImpl(private val networkApi: UpbitApi) : RemoteTickerDataSource {
+ override suspend fun getAllTicker(): Any = networkApi.getMarket()
+ override suspend fun getTicker(currency: String): Any = networkApi.getTicker(currency)
+ override suspend fun getExchangeTicker(currency: String): Any = networkApi.getExchangeTicker(currency)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/sunday/di/NetworkModule.kt b/app/src/main/java/com/example/sunday/di/NetworkModule.kt
new file mode 100644
index 0000000..743fe20
--- /dev/null
+++ b/app/src/main/java/com/example/sunday/di/NetworkModule.kt
@@ -0,0 +1,47 @@
+package com.example.sunday.di
+
+import com.example.sunday.network.api.BithumbApi
+import com.example.sunday.network.api.CoinoneApi
+import com.example.sunday.network.api.UpbitApi
+import org.koin.dsl.module
+import retrofit2.CallAdapter
+import retrofit2.Converter
+import retrofit2.Retrofit
+import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
+import retrofit2.converter.gson.GsonConverterFactory
+
+private const val UPBIT_URL = "https://api.upbit.com"
+private const val BITHUMB_URL = "https://api.bithumb.com"
+private const val COINONE_URL = "https://api.coinone.co.kr"
+
+val networkModuelUpbit = module {
+ single {
+ Retrofit.Builder()
+ .addConverterFactory(get())
+ .addCallAdapterFactory(get())
+ .baseUrl(UPBIT_URL)
+ .build()
+ .create(UpbitApi::class.java)
+ }
+
+ single {
+ Retrofit.Builder()
+ .addConverterFactory(get())
+ .addCallAdapterFactory(get())
+ .baseUrl(BITHUMB_URL)
+ .build()
+ .create(BithumbApi::class.java)
+ }
+
+ single{
+ Retrofit.Builder()
+ .addConverterFactory(get())
+ .addCallAdapterFactory(get())
+ .baseUrl(COINONE_URL)
+ .build()
+ .create(CoinoneApi::class.java)
+ }
+
+ single { GsonConverterFactory.create() as Converter.Factory }
+ single { RxJava2CallAdapterFactory.create() as CallAdapter.Factory }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/sunday/di/ViewModelModule.kt b/app/src/main/java/com/example/sunday/di/ViewModelModule.kt
new file mode 100644
index 0000000..528a0a7
--- /dev/null
+++ b/app/src/main/java/com/example/sunday/di/ViewModelModule.kt
@@ -0,0 +1,27 @@
+package com.example.sunday.di
+
+import com.example.sunday.data.enums.Exchange
+import com.example.sunday.data.repository.ticker.BithumbRepository
+import com.example.sunday.data.repository.ticker.CoinoneRepository
+import com.example.sunday.data.repository.ticker.TickerRepository
+import com.example.sunday.data.repository.ticker.UpbitRepository
+import com.example.sunday.data.soruce.remote.RemoteBitumbDataSoruceImpl
+import com.example.sunday.data.soruce.remote.RemoteCoinoneDataSourceImpl
+import com.example.sunday.data.soruce.remote.RemoteUpbitDataSourceImpl
+import com.example.sunday.viewmodel.ExchangeViewModel
+import com.example.sunday.viewmodel.MainViewModel
+import org.koin.androidx.viewmodel.dsl.viewModel
+import org.koin.dsl.module
+
+val viewModelModule = module {
+ viewModel { MainViewModel(
+ mapOf(Exchange.UPBIT.exchangeName to UpbitRepository(RemoteUpbitDataSourceImpl(get())) as TickerRepository,
+ Exchange.BITHUMB.exchangeName to BithumbRepository(RemoteBitumbDataSoruceImpl(get())) as TickerRepository,
+ Exchange.COINONE.exchangeName to CoinoneRepository(RemoteCoinoneDataSourceImpl(get())) as TickerRepository)) }
+
+ viewModel { ExchangeViewModel(
+ mapOf(Exchange.UPBIT.exchangeName to UpbitRepository(RemoteUpbitDataSourceImpl(get())) as TickerRepository,
+ Exchange.BITHUMB.exchangeName to BithumbRepository(RemoteBitumbDataSoruceImpl(get())) as TickerRepository,
+ Exchange.COINONE.exchangeName to CoinoneRepository(RemoteCoinoneDataSourceImpl(get())) as TickerRepository)) }
+}
+
diff --git a/app/src/main/java/com/example/sunday/network/api/BithumbApi.kt b/app/src/main/java/com/example/sunday/network/api/BithumbApi.kt
new file mode 100644
index 0000000..2825604
--- /dev/null
+++ b/app/src/main/java/com/example/sunday/network/api/BithumbApi.kt
@@ -0,0 +1,15 @@
+package com.example.sunday.network.api
+
+import com.example.sunday.network.response.bithumb.BithumbAllResponse
+import retrofit2.http.GET
+import retrofit2.http.Path
+
+interface BithumbApi {
+
+ @GET("/public/ticker/all")
+ suspend fun getTickerList(): BithumbAllResponse
+
+
+ @GET("/public/ticker/{exchangeName}")
+ suspend fun getExchangeTicker(@Path("exchangeName") exchangeName: String) : BithumbAllResponse
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/sunday/network/api/CoinoneApi.kt b/app/src/main/java/com/example/sunday/network/api/CoinoneApi.kt
new file mode 100644
index 0000000..3f00c77
--- /dev/null
+++ b/app/src/main/java/com/example/sunday/network/api/CoinoneApi.kt
@@ -0,0 +1,17 @@
+package com.example.sunday.network.api
+
+import com.example.sunday.network.response.coinone.CoinoneResponse
+import retrofit2.http.GET
+import retrofit2.http.Query
+
+interface CoinoneApi {
+
+ @GET("/ticker/?currency=all")
+ suspend fun getAllTicker(): Map
+
+ @GET("/ticker/?")
+ suspend fun getTicker(@Query("currency") currency: String): CoinoneResponse
+
+ @GET("/ticker/?")
+ suspend fun getExchangeTicker(@Query("currency") currency: String): CoinoneResponse
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/sunday/network/api/UpbitApi.kt b/app/src/main/java/com/example/sunday/network/api/UpbitApi.kt
new file mode 100644
index 0000000..7aad649
--- /dev/null
+++ b/app/src/main/java/com/example/sunday/network/api/UpbitApi.kt
@@ -0,0 +1,19 @@
+package com.example.sunday.network.api
+
+import com.example.sunday.network.response.upbit.UpbitMarketResponse
+import com.example.sunday.network.response.upbit.UpbitTickerResponse
+import retrofit2.http.GET
+import retrofit2.http.Query
+
+interface UpbitApi {
+
+ @GET("/v1/market/all")
+ suspend fun getMarket(): List
+
+ @GET("/v1/ticker?")
+ suspend fun getTicker(@Query("markets") markets: String) : List
+
+ @GET("/v1/ticker?")
+ suspend fun getExchangeTicker(@Query("markets") markets: String) : List
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/sunday/network/response/bithumb/BithumbAllResponse.kt b/app/src/main/java/com/example/sunday/network/response/bithumb/BithumbAllResponse.kt
new file mode 100644
index 0000000..48e96d7
--- /dev/null
+++ b/app/src/main/java/com/example/sunday/network/response/bithumb/BithumbAllResponse.kt
@@ -0,0 +1,10 @@
+package com.example.sunday.network.response.bithumb
+
+import com.google.gson.annotations.SerializedName
+
+data class BithumbAllResponse(
+ @SerializedName("status")
+ val status: String,
+ @SerializedName("data")
+ val item: HashMap
+)
\ No newline at end of file
diff --git a/app/src/main/java/com/example/sunday/network/response/bithumb/BithumbTickerResponse.kt b/app/src/main/java/com/example/sunday/network/response/bithumb/BithumbTickerResponse.kt
new file mode 100644
index 0000000..6936958
--- /dev/null
+++ b/app/src/main/java/com/example/sunday/network/response/bithumb/BithumbTickerResponse.kt
@@ -0,0 +1,51 @@
+package com.example.sunday.network.response.bithumb
+
+import com.example.sunday.data.model.ExchangeTicker
+import com.example.sunday.data.model.Ticker
+import com.example.sunday.data.model.TickerProvider
+import com.google.gson.annotations.SerializedName
+
+data class BithumbTickerResponse(
+ @SerializedName("acc_trade_value")
+ val accTradeValue: String,
+ @SerializedName("acc_trade_value_24H")
+ val accTradeValue24H: Double,
+ @SerializedName("closing_price")
+ val closingPrice: Double,
+ @SerializedName("fluctate_24H")
+ val fluctate24H: Double,
+ @SerializedName("fluctate_rate_24H")
+ val fluctateRate24H: String,
+ @SerializedName("max_price")
+ val maxPrice: Double,
+ @SerializedName("min_price")
+ val minPrice: Double,
+ @SerializedName("opening_price")
+ val openingPrice: Double,
+ @SerializedName("prev_closing_price")
+ val prevClosingPrice: Double,
+ @SerializedName("units_traded")
+ val unitsTraded: String,
+ @SerializedName("units_traded_24H")
+ val unitsTraded24H: String
+) : TickerProvider{
+ override fun toTicker() =
+ Ticker(baseCurrency = "KRW",
+ last = closingPrice,
+ high = maxPrice,
+ low = minPrice,
+ diff = fluctate24H,
+ volume = accTradeValue24H)
+
+ fun toTicker(name: String) =
+ Ticker(currency = name,
+ baseCurrency = "KRW",
+ last = closingPrice,
+ high = maxPrice,
+ low = minPrice,
+ diff = fluctate24H,
+ volume = accTradeValue24H)
+
+ override fun toExchangeTicker(exchangeName: String): ExchangeTicker =
+ ExchangeTicker(exchangeName, toTicker())
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/sunday/network/response/coinone/CoinoneResponse.kt b/app/src/main/java/com/example/sunday/network/response/coinone/CoinoneResponse.kt
new file mode 100644
index 0000000..931a7e5
--- /dev/null
+++ b/app/src/main/java/com/example/sunday/network/response/coinone/CoinoneResponse.kt
@@ -0,0 +1,53 @@
+package com.example.sunday.network.response.coinone
+
+
+import com.example.sunday.data.model.ExchangeTicker
+import com.example.sunday.data.model.Ticker
+import com.example.sunday.data.model.TickerProvider
+import com.google.gson.annotations.SerializedName
+
+data class CoinoneResponse(
+ @SerializedName("currency")
+ val currency: String,
+ @SerializedName("errorCode")
+ val errorCode: String,
+ @SerializedName("first")
+ val first: Double,
+ @SerializedName("high")
+ val high: Double,
+ @SerializedName("last")
+ val last: Double,
+ @SerializedName("low")
+ val low: Double,
+ @SerializedName("result")
+ val result: String,
+ @SerializedName("timestamp")
+ val timestamp: String,
+ @SerializedName("volume")
+ val volume: Double,
+ @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
+) : TickerProvider{
+ override fun toTicker(): Ticker {
+ val diff = (last - first) / first * 100
+ return Ticker(currency,
+ baseCurrency = "KRW",
+ last = last,
+ high = high,
+ low = low,
+ diff = diff,
+ volume = volume * last)
+
+ }
+
+ override fun toExchangeTicker(exchangeName: String): ExchangeTicker =
+ ExchangeTicker(exchangeName, toTicker())
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/sunday/network/response/upbit/UpbitMarketResponse.kt b/app/src/main/java/com/example/sunday/network/response/upbit/UpbitMarketResponse.kt
new file mode 100644
index 0000000..0ca6f84
--- /dev/null
+++ b/app/src/main/java/com/example/sunday/network/response/upbit/UpbitMarketResponse.kt
@@ -0,0 +1,12 @@
+package com.example.sunday.network.response.upbit
+
+import com.google.gson.annotations.SerializedName
+
+data class UpbitMarketResponse (
+ @SerializedName("english_name")
+ val englishName: String,
+ @SerializedName("korean_name")
+ val koreanName: String,
+ @SerializedName("market")
+ val market: String
+)
\ No newline at end of file
diff --git a/app/src/main/java/com/example/sunday/network/response/upbit/UpbitTickerResponse.kt b/app/src/main/java/com/example/sunday/network/response/upbit/UpbitTickerResponse.kt
new file mode 100644
index 0000000..8c165df
--- /dev/null
+++ b/app/src/main/java/com/example/sunday/network/response/upbit/UpbitTickerResponse.kt
@@ -0,0 +1,74 @@
+package com.example.sunday.network.response.upbit
+
+import com.example.sunday.data.model.ExchangeTicker
+import com.example.sunday.data.model.Ticker
+import com.example.sunday.data.model.TickerProvider
+import com.google.gson.annotations.SerializedName
+
+data class UpbitTickerResponse (
+ @SerializedName("acc_trade_price")
+ val accTradePrice: Double,
+ @SerializedName("acc_trade_price_24h")
+ val accTradePrice24h: Double,
+ @SerializedName("acc_trade_volume")
+ val accTradeVolume: Double,
+ @SerializedName("acc_trade_volume_24h")
+ val accTradeVolume24h: Double,
+ @SerializedName("change")
+ val change: String,
+ @SerializedName("change_price")
+ val changePrice: Double,
+ @SerializedName("change_rate")
+ val changeRate: Double,
+ @SerializedName("high_price")
+ val highPrice: Double,
+ @SerializedName("highest_52_week_date")
+ val highest52WeekDate: String,
+ @SerializedName("highest_52_week_price")
+ val highest52WeekPrice: Double,
+ @SerializedName("low_price")
+ val lowPrice: Double,
+ @SerializedName("lowest_52_week_date")
+ val lowest52WeekDate: String,
+ @SerializedName("lowest_52_week_price")
+ val lowest52WeekPrice: Double,
+ @SerializedName("market")
+ val market: String,
+ @SerializedName("opening_price")
+ val openingPrice: Double,
+ @SerializedName("prev_closing_price")
+ val prevClosingPrice: Double,
+ @SerializedName("signed_change_price")
+ val signedChangePrice: Double,
+ @SerializedName("signed_change_rate")
+ val signedChangeRate: Double,
+ @SerializedName("timestamp")
+ val timestamp: Long,
+ @SerializedName("trade_date")
+ val tradeDate: String,
+ @SerializedName("trade_date_kst")
+ val tradeDateKst: String,
+ @SerializedName("trade_price")
+ val tradePrice: Double,
+ @SerializedName("trade_time")
+ val tradeTime: String,
+ @SerializedName("trade_time_kst")
+ val tradeTimeKst: String,
+ @SerializedName("trade_timestamp")
+ val tradeTimestamp: Long,
+ @SerializedName("trade_volume")
+ val tradeVolume: Double
+) : TickerProvider{
+ override fun toTicker() =
+ Ticker(
+ currency = market.split("-")[1],
+ baseCurrency = market.split("-")[0],
+ last = tradePrice,
+ high = highPrice,
+ low = lowPrice,
+ diff = changeRate * if (change == "RISE" ) 100 else -100,
+ volume = accTradeVolume24h)
+
+ override fun toExchangeTicker(exchangeName: String): ExchangeTicker =
+ ExchangeTicker(exchangeName, toTicker())
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/sunday/ui/CoinAdapter.kt b/app/src/main/java/com/example/sunday/ui/CoinAdapter.kt
new file mode 100644
index 0000000..3c4817c
--- /dev/null
+++ b/app/src/main/java/com/example/sunday/ui/CoinAdapter.kt
@@ -0,0 +1,44 @@
+package com.example.sunday.ui
+
+import android.view.ViewGroup
+import androidx.recyclerview.widget.RecyclerView
+import com.example.sunday.R
+import com.example.sunday.base.BaseViewHolder
+import com.example.sunday.databinding.ItemCoinBinding
+import com.example.sunday.ui.listener.ItemClickListener
+import com.example.sunday.ui.model.UTicker
+
+class CoinAdapter : RecyclerView.Adapter() {
+
+ private val data = mutableListOf()
+ private lateinit var itemClickListener: ItemClickListener
+
+ fun setData(newData: List?){
+ if(newData != null){
+ data.clear()
+ data.addAll(newData)
+ notifyDataSetChanged()
+ }
+ }
+
+ fun setItemClickListner(itemClickListener: ItemClickListener){
+ this.itemClickListener = itemClickListener
+ }
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CoinViewHolder = CoinViewHolder(parent)
+
+ override fun getItemCount(): Int = data.size
+
+ override fun onBindViewHolder(holder: CoinViewHolder, position: Int) {
+ holder.bindTo(data[position])
+ holder.itemView.setOnClickListener { itemClickListener.onClick(it, data[position].name!!) }
+ }
+
+
+ class CoinViewHolder(parent: ViewGroup): BaseViewHolder(R.layout.item_coin, parent){
+ fun bindTo(uTicker: UTicker){
+ binding.item = uTicker
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/sunday/ui/ExchangeActivity.kt b/app/src/main/java/com/example/sunday/ui/ExchangeActivity.kt
new file mode 100644
index 0000000..6a3d736
--- /dev/null
+++ b/app/src/main/java/com/example/sunday/ui/ExchangeActivity.kt
@@ -0,0 +1,33 @@
+package com.example.sunday.ui
+
+import android.os.Bundle
+import com.example.sunday.R
+import com.example.sunday.base.BaseActivity
+import com.example.sunday.databinding.ActivityExchangeBinding
+import com.example.sunday.viewmodel.ExchangeViewModel
+import org.koin.androidx.viewmodel.ext.android.viewModel
+
+class ExchangeActivity : BaseActivity(R.layout.activity_exchange) {
+
+ private val viewModel by viewModel()
+ private val exchangeAdapter by lazy { ExchangeAdapter() }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ initViewModel()
+ initRecyclerView()
+ viewModel.getExchangeTicker()
+ }
+
+ fun initViewModel(){
+ viewModel.liveCurrency.value = intent.getStringExtra("currency")
+ binding.vm = viewModel
+ }
+
+ fun initRecyclerView(){
+ with(binding.recyclerViewExchange){
+ adapter = exchangeAdapter
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/sunday/ui/ExchangeAdapter.kt b/app/src/main/java/com/example/sunday/ui/ExchangeAdapter.kt
new file mode 100644
index 0000000..7b20b52
--- /dev/null
+++ b/app/src/main/java/com/example/sunday/ui/ExchangeAdapter.kt
@@ -0,0 +1,38 @@
+package com.example.sunday.ui
+
+import android.view.ViewGroup
+import androidx.recyclerview.widget.RecyclerView
+import com.example.sunday.R
+import com.example.sunday.base.BaseViewHolder
+import com.example.sunday.databinding.ItemExchangeBinding
+import com.example.sunday.ui.model.ETicker
+
+class ExchangeAdapter : RecyclerView.Adapter() {
+
+ private val data = mutableListOf()
+
+ fun setData(newData: List?){
+ if(newData != null){
+ data.clear()
+ data.addAll(newData)
+ notifyDataSetChanged()
+ }
+ }
+
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ExchangeViewHolder = ExchangeViewHolder(parent)
+
+ override fun getItemCount(): Int = data.size
+
+ override fun onBindViewHolder(holder: ExchangeViewHolder, position: Int) {
+ holder.binnTo(data[position])
+ }
+
+
+ class ExchangeViewHolder(parent: ViewGroup): BaseViewHolder(R.layout.item_exchange, parent) {
+ fun binnTo(exchangeTicker: ETicker){
+ binding.item = exchangeTicker
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/sunday/ui/MainActivity.kt b/app/src/main/java/com/example/sunday/ui/MainActivity.kt
new file mode 100644
index 0000000..33faf76
--- /dev/null
+++ b/app/src/main/java/com/example/sunday/ui/MainActivity.kt
@@ -0,0 +1,45 @@
+package com.example.sunday.ui
+
+import android.content.Intent
+import android.os.Bundle
+import android.view.View
+import com.example.sunday.R
+import com.example.sunday.base.BaseActivity
+import com.example.sunday.data.enums.BaseCurrency
+import com.example.sunday.databinding.ActivityMainBinding
+import com.example.sunday.ui.listener.ItemClickListener
+import com.example.sunday.viewmodel.MainViewModel
+import org.koin.androidx.viewmodel.ext.android.viewModel
+
+class MainActivity : BaseActivity(R.layout.activity_main) {
+
+ private val viewModel by viewModel()
+ private val coinAdapter by lazy { CoinAdapter() }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ initViewModel()
+ initRecyclerView()
+ viewModel.getTicker(BaseCurrency.KRW.toString())
+ }
+
+ fun initViewModel(){
+ binding.vm = viewModel
+ }
+
+ fun initRecyclerView(){
+ with(binding.recyclerView){
+ coinAdapter.setItemClickListner( object : ItemClickListener {
+ override fun onClick(view: View, currency: String) {
+ val intent = Intent(this@MainActivity, ExchangeActivity::class.java).run {
+ putExtra("currency", currency)
+ }
+ startActivity(intent)
+ }
+ })
+ adapter = coinAdapter
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/sunday/ui/listener/ItemClickListener.kt b/app/src/main/java/com/example/sunday/ui/listener/ItemClickListener.kt
new file mode 100644
index 0000000..3ee1c68
--- /dev/null
+++ b/app/src/main/java/com/example/sunday/ui/listener/ItemClickListener.kt
@@ -0,0 +1,7 @@
+package com.example.sunday.ui.listener
+
+import android.view.View
+
+interface ItemClickListener {
+ fun onClick(view: View, currency: String)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/sunday/ui/model/ETicker.kt b/app/src/main/java/com/example/sunday/ui/model/ETicker.kt
new file mode 100644
index 0000000..1f5b9c2
--- /dev/null
+++ b/app/src/main/java/com/example/sunday/ui/model/ETicker.kt
@@ -0,0 +1,8 @@
+package com.example.sunday.ui.model
+
+data class ETicker(
+ var idx: Int? = 0,
+ val exchangeName: String?,
+ val nowPrice: Double?,
+ val volume: Double?
+)
\ No newline at end of file
diff --git a/app/src/main/java/com/example/sunday/ui/model/UTicker.kt b/app/src/main/java/com/example/sunday/ui/model/UTicker.kt
new file mode 100644
index 0000000..cbd53a7
--- /dev/null
+++ b/app/src/main/java/com/example/sunday/ui/model/UTicker.kt
@@ -0,0 +1,9 @@
+package com.example.sunday.ui.model
+
+data class UTicker(
+ val name: String?,
+ val last1: Double?,
+ val last2: Double?,
+ val last3: Double?,
+ val exchange: String
+)
\ No newline at end of file
diff --git a/app/src/main/java/com/example/sunday/util/BindingAdapters.kt b/app/src/main/java/com/example/sunday/util/BindingAdapters.kt
new file mode 100644
index 0000000..15e46b1
--- /dev/null
+++ b/app/src/main/java/com/example/sunday/util/BindingAdapters.kt
@@ -0,0 +1,19 @@
+package com.example.sunday.util
+
+import androidx.databinding.BindingAdapter
+import androidx.recyclerview.widget.RecyclerView
+import com.example.sunday.ui.CoinAdapter
+import com.example.sunday.ui.ExchangeAdapter
+import com.example.sunday.ui.model.ETicker
+import com.example.sunday.ui.model.UTicker
+
+
+@BindingAdapter("setData")
+fun RecyclerView.setData(list: List?) {
+ (adapter as? CoinAdapter)?.setData(list)
+}
+
+@BindingAdapter("setETicker")
+fun RecyclerView.setETicker(list: List?) {
+ (adapter as? ExchangeAdapter)?.setData(list)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/sunday/util/SchedulerExtension.kt b/app/src/main/java/com/example/sunday/util/SchedulerExtension.kt
new file mode 100644
index 0000000..16a21f8
--- /dev/null
+++ b/app/src/main/java/com/example/sunday/util/SchedulerExtension.kt
@@ -0,0 +1,24 @@
+package com.example.sunday.util
+
+import io.reactivex.Completable
+import io.reactivex.Observable
+import io.reactivex.Single
+import io.reactivex.android.schedulers.AndroidSchedulers
+import io.reactivex.disposables.CompositeDisposable
+import io.reactivex.disposables.Disposable
+import io.reactivex.schedulers.Schedulers
+
+
+operator fun CompositeDisposable.plusAssign(disposable: Disposable){
+ this.add((disposable))
+}
+
+
+fun Single.withSchedulers(): Single =
+ subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
+
+fun Observable.withSchedulers(): Observable =
+ subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
+
+fun Completable.withSchedulers(): Completable =
+ subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
\ No newline at end of file
diff --git a/app/src/main/java/com/example/sunday/util/TextViewExtension.kt b/app/src/main/java/com/example/sunday/util/TextViewExtension.kt
new file mode 100644
index 0000000..44e7b29
--- /dev/null
+++ b/app/src/main/java/com/example/sunday/util/TextViewExtension.kt
@@ -0,0 +1,40 @@
+package com.example.sunday.util
+
+import android.widget.TextView
+import androidx.core.content.res.ResourcesCompat
+import androidx.databinding.BindingAdapter
+import com.example.sunday.R
+import com.example.sunday.network.response.upbit.UpbitTickerResponse
+import java.text.DecimalFormat
+
+
+@BindingAdapter("floatNumber")
+fun TextView.setFloatNumber(tmp: Double){
+ text = DecimalFormat("0.###").format(tmp)
+}
+@BindingAdapter("intNumber")
+fun TextView.setIntNumber(tmp: Int){
+ text = tmp.toString()
+}
+
+@BindingAdapter("coinName")
+fun TextView.setCoinName(upbitTickerResponse: UpbitTickerResponse){
+ text = upbitTickerResponse.market.split("-")[1]
+}
+
+@BindingAdapter("compareRise")
+fun TextView.setCompareRise(upbitTickerResponse: UpbitTickerResponse){
+ upbitTickerResponse.change.let{
+ when{
+ it.equals("RISE") -> {
+ setTextColor(ResourcesCompat.getColor(resources, R.color.colorBlue, null))
+ }
+ it.equals("FALL") -> {
+ setTextColor(ResourcesCompat.getColor(resources, R.color.colorRed, null))
+ }
+ else -> {
+ setTextColor(ResourcesCompat.getColor(resources, R.color.colorGray, null))
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/sunday/viewmodel/ExchangeViewModel.kt b/app/src/main/java/com/example/sunday/viewmodel/ExchangeViewModel.kt
new file mode 100644
index 0000000..b4403db
--- /dev/null
+++ b/app/src/main/java/com/example/sunday/viewmodel/ExchangeViewModel.kt
@@ -0,0 +1,91 @@
+package com.example.sunday.viewmodel
+
+import android.util.Log
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import com.example.sunday.data.enums.BaseCurrency
+import com.example.sunday.data.enums.Exchange
+import com.example.sunday.data.model.ExchangeTicker
+import com.example.sunday.data.repository.ticker.TickerRepository
+import com.example.sunday.network.response.bithumb.BithumbAllResponse
+import com.example.sunday.network.response.bithumb.BithumbTickerResponse
+import com.example.sunday.network.response.coinone.CoinoneResponse
+import com.example.sunday.network.response.upbit.UpbitTickerResponse
+import com.example.sunday.ui.model.ETicker
+import com.google.gson.Gson
+import io.reactivex.disposables.CompositeDisposable
+import kotlinx.coroutines.*
+
+
+class ExchangeViewModel(private val repoMap: Map) : ViewModel() {
+
+ private val handler = CoroutineExceptionHandler { _, exception -> Log.e("Coroutines ExchangeViewModel ::","Caught $exception") }
+
+ private val compositeDisposable = CompositeDisposable()
+
+ private val _tickerList = MutableLiveData>()
+ val tickerList: LiveData> get() = _tickerList
+
+ val liveCurrency = MutableLiveData()
+
+ fun getExchangeTicker(): Job{
+ return viewModelScope.launch(handler) {
+ try{
+
+ val t1 = async { getUpbitExchangeTickerList() }
+ val t2 = async { getBithumbExchangeTickerList() }
+ val t3 = async { getCoinoneExchangeTickerList() }
+ _tickerList.value = computeResult(t1.await(),t2.await(), t3.await())
+
+ }catch (error: Exception){
+ Log.e("error::", error.toString())
+ }
+
+ }
+
+ }
+ private suspend fun computeResult(t1: List, t2: ExchangeTicker, t3: ExchangeTicker): MutableList {
+ val list: MutableList = mutableListOf()
+ withContext(Dispatchers.IO){
+ list.add(ETicker(0,t1[0].exchangeName, t1[0].last, t1[0].volume))
+ list.add(ETicker(0,t2.exchangeName, t2.last, t2.volume))
+ list.add(ETicker(0,t3.exchangeName, t3.last, t3.volume))
+ val sortedWith = list.sortedWith(Comparator { a: ETicker, b: ETicker ->
+ when {
+ a.nowPrice!! > b.nowPrice!! -> 1
+ a.nowPrice!! < b.nowPrice!! -> -1
+ else -> 0
+ }
+ })
+ sortedWith.forEachIndexed { index, eTicker -> eTicker.idx = index + 1 }
+ }
+ return list
+ }
+
+ private suspend fun getUpbitExchangeTickerList(): List{
+ return (repoMap[Exchange.UPBIT.exchangeName]?.getExchangeTicker("${BaseCurrency.KRW}-${liveCurrency.value}") as List)
+ .map{
+ it.toExchangeTicker(Exchange.UPBIT.exchangeName)
+ }
+ }
+
+ private suspend fun getBithumbExchangeTickerList(): ExchangeTicker{
+ return (repoMap[Exchange.BITHUMB.exchangeName]?.getExchangeTicker(liveCurrency.value!!) as BithumbAllResponse)
+ .let{
+ val gson = Gson()
+ gson.fromJson(it.item.toString(), BithumbTickerResponse::class.java).toExchangeTicker(Exchange.BITHUMB.exchangeName)
+ }
+ }
+
+ private suspend fun getCoinoneExchangeTickerList(): ExchangeTicker {
+ return (repoMap[Exchange.COINONE.exchangeName]?.getExchangeTicker(liveCurrency.value!!) as CoinoneResponse).toExchangeTicker(Exchange.COINONE.exchangeName)
+ }
+
+
+ override fun onCleared() {
+ super.onCleared()
+ compositeDisposable.dispose()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/sunday/viewmodel/MainViewModel.kt b/app/src/main/java/com/example/sunday/viewmodel/MainViewModel.kt
new file mode 100644
index 0000000..fe50d49
--- /dev/null
+++ b/app/src/main/java/com/example/sunday/viewmodel/MainViewModel.kt
@@ -0,0 +1,109 @@
+package com.example.sunday.viewmodel
+
+import android.util.Log
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import com.example.sunday.data.enums.Exchange
+import com.example.sunday.data.model.Ticker
+import com.example.sunday.data.repository.ticker.TickerRepository
+import com.example.sunday.network.response.bithumb.BithumbAllResponse
+import com.example.sunday.network.response.bithumb.BithumbTickerResponse
+import com.example.sunday.network.response.coinone.CoinoneResponse
+import com.example.sunday.network.response.upbit.UpbitMarketResponse
+import com.example.sunday.network.response.upbit.UpbitTickerResponse
+import com.example.sunday.ui.model.UTicker
+import com.google.gson.Gson
+import io.reactivex.disposables.CompositeDisposable
+import kotlinx.coroutines.*
+import kotlin.math.min
+
+class MainViewModel(private val repoMap: Map) : ViewModel() {
+
+
+ private val handler = CoroutineExceptionHandler { _, exception -> Log.e("Coroutines MainViewModel::","Caught $exception") }
+
+ private val compositeDisposable = CompositeDisposable()
+
+ private val _tickerList = MutableLiveData>()
+ val tickerList: LiveData> get() = _tickerList
+
+ fun getTicker(baseCurrency: String): Job{
+ return viewModelScope.launch(handler) {
+ try{
+ val upbitMarketData = getUpbitMarketData(baseCurrency)
+ val t1 = async { getUpbitTickerData(upbitMarketData) }
+ val t2 = async { getBithumbTickerList() }
+ val t3 = async { getCoinoneTickerList() }
+ _tickerList.value = computeResult(t1.await(), t2.await(), t3.await())
+
+ }catch (error: Exception){
+ Log.e("Coroutine ::", error.toString())
+ }
+ }
+ }
+
+ private suspend fun computeResult(t1: List, t2: List, t3: List):MutableList {
+ val list: MutableList = mutableListOf()
+ withContext(Dispatchers.IO){
+ t1.forEach {
+ val name: String? = it.currency?.toUpperCase()
+ val last1: Double? = it.last
+ t2.forEach{
+ val last2: Double? = it.last
+ if(name == it.currency?.toUpperCase()){
+ t3.forEach {
+ val last3: Double? = it.last
+ if(name == it.currency?.toUpperCase()){
+ list.add(UTicker(name,last1,last2,last3,
+ when(min(min(last1!!, last2!!), last3!!)){
+ last1 -> Exchange.UPBIT.exchangeName
+ last2 -> Exchange.BITHUMB.exchangeName
+ else -> Exchange.COINONE.exchangeName
+ }))
+
+ return@forEach
+ }
+ }
+ return@forEach
+ }
+ }
+ }
+ }
+ return list
+ }
+
+ private suspend fun getUpbitMarketData(baseCurrency: String): List{
+ return (repoMap[Exchange.UPBIT.exchangeName]?.getAllTicker() as List)
+ .map { it.market }
+ .filter { it.split("-")[0] == baseCurrency }
+ .toList()
+ }
+
+ private suspend fun getUpbitTickerData(list: List): List {
+ return (repoMap[Exchange.UPBIT.exchangeName]?.getTicker(list.joinToString()) as List)
+ .map { it.toTicker()}
+ }
+
+ private suspend fun getBithumbTickerList(): List{
+ val gson = Gson()
+ return (repoMap[Exchange.BITHUMB.exchangeName]?.getAllTicker() as BithumbAllResponse)
+ .item
+ .filter { it.key != "date" }
+ .map {(name, response) -> gson.fromJson(response.toString(), BithumbTickerResponse::class.java).toTicker(name)}
+ }
+
+ private suspend fun getCoinoneTickerList(): List{
+ val gson = Gson()
+ return (repoMap[Exchange.COINONE.exchangeName]?.getAllTicker() as Map)
+ .filter { it.key != "errorCode" && it.key != "timestamp" && it.key != "result" }
+ .map { gson.fromJson(it.value.toString(), CoinoneResponse::class.java).toTicker() }
+ }
+
+
+ override fun onCleared() {
+ super.onCleared()
+ compositeDisposable.dispose()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
new file mode 100644
index 0000000..1f6bb29
--- /dev/null
+++ b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 0000000..0d025f9
--- /dev/null
+++ b/app/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,170 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_exchange.xml b/app/src/main/res/layout/activity_exchange.xml
new file mode 100644
index 0000000..c1b239b
--- /dev/null
+++ b/app/src/main/res/layout/activity_exchange.xml
@@ -0,0 +1,88 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..462db78
--- /dev/null
+++ b/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,99 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/item_coin.xml b/app/src/main/res/layout/item_coin.xml
new file mode 100644
index 0000000..f419b98
--- /dev/null
+++ b/app/src/main/res/layout/item_coin.xml
@@ -0,0 +1,89 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/item_exchange.xml b/app/src/main/res/layout/item_exchange.xml
new file mode 100644
index 0000000..6fb1f5e
--- /dev/null
+++ b/app/src/main/res/layout/item_exchange.xml
@@ -0,0 +1,78 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 0000000..eca70cf
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 0000000..eca70cf
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..898f3ed
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 0000000..dffca36
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..64ba76f
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 0000000..dae5e08
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..e5ed465
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..14ed0af
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..b0907ca
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..d8ae031
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..2c18de9
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..beed3cd
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
new file mode 100644
index 0000000..1fd5cd6
--- /dev/null
+++ b/app/src/main/res/values/colors.xml
@@ -0,0 +1,9 @@
+
+
+ #008577
+ #00574B
+ #D81B60
+ #8e8e8e
+ #ff0000
+ #0000ff
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..a2e5bba
--- /dev/null
+++ b/app/src/main/res/values/strings.xml
@@ -0,0 +1,14 @@
+
+ Sunday
+ 코인명
+ 업비트
+ 빗썸
+ 코인원
+ 추천거래소
+
+
+ 순위
+ 거래소
+ 현재
+ 거래대금
+
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
new file mode 100644
index 0000000..5885930
--- /dev/null
+++ b/app/src/main/res/values/styles.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
diff --git a/app/src/test/java/com/example/sunday/ExampleUnitTest.kt b/app/src/test/java/com/example/sunday/ExampleUnitTest.kt
new file mode 100644
index 0000000..ca235b9
--- /dev/null
+++ b/app/src/test/java/com/example/sunday/ExampleUnitTest.kt
@@ -0,0 +1,16 @@
+package com.example.sunday
+
+import org.junit.Assert.assertEquals
+import org.junit.Test
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+class ExampleUnitTest {
+ @Test
+ fun addition_isCorrect() {
+ assertEquals(4, 2 + 2)
+ }
+}
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 0000000..819d034
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,28 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+
+buildscript {
+ ext.kotlin_version = '1.3.61'
+ repositories {
+ google()
+ jcenter()
+
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:3.5.3'
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+ // NOTE: Do not place your application dependencies here; they belong
+ // in the individual module build.gradle files
+ }
+}
+
+allprojects {
+ repositories {
+ google()
+ jcenter()
+
+ }
+}
+
+task clean(type: Delete) {
+ delete rootProject.buildDir
+}
diff --git a/gradle.properties b/gradle.properties
new file mode 100644
index 0000000..23339e0
--- /dev/null
+++ b/gradle.properties
@@ -0,0 +1,21 @@
+# Project-wide Gradle settings.
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx1536m
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
+# AndroidX package structure to make it clearer which packages are bundled with the
+# Android operating system, and which are packaged with your app's APK
+# https://developer.android.com/topic/libraries/support-library/androidx-rn
+android.useAndroidX=true
+# Automatically convert third-party libraries to use AndroidX
+android.enableJetifier=true
+# Kotlin code style for this project: "official" or "obsolete":
+kotlin.code.style=official
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..f6b961f
Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..702abe8
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Sun Jan 05 12:04:08 KST 2020
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip
diff --git a/gradlew b/gradlew
new file mode 100755
index 0000000..cccdd3d
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,172 @@
+#!/usr/bin/env sh
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+ cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 0000000..f955316
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,84 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/settings.gradle b/settings.gradle
new file mode 100644
index 0000000..ab48105
--- /dev/null
+++ b/settings.gradle
@@ -0,0 +1,2 @@
+include ':app'
+rootProject.name='Sunday'