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>) { + (this.adapter as? BaseRecyclerView.BaseAdapter)?.run { + setItems(items) + notifyDataSetChanged() + } +} \ No newline at end of file diff --git a/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/presentation/ticker/TickerViewModel.kt b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/presentation/ticker/TickerViewModel.kt new file mode 100644 index 0000000..4dca6ec --- /dev/null +++ b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/presentation/ticker/TickerViewModel.kt @@ -0,0 +1,84 @@ +package sample.nackun.com.studyfirst.presentation.ticker + +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.GetBithumbTickersUseCase +import sample.nackun.com.studyfirst.domain.usecase.GetCoinOneTickersUseCase +import sample.nackun.com.studyfirst.domain.usecase.GetUpbitMarketUseCase +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 TickerViewModel( + private val getUpbitMarketUseCase: GetUpbitMarketUseCase, + private val getUpbitTickersUseCase: GetUpbitTickersUseCase, + private val getBithumbTickersUseCase: GetBithumbTickersUseCase, + private val getCoinOneTickersUseCase: GetCoinOneTickersUseCase +) : BaseViewModel() { + + private val firstMarketName = "KRW" + + private val _tickers = MutableLiveData>>() + val tickers: LiveData>> get() = _tickers + private val _selectedMarket = MutableLiveData() + val selectedMarket: LiveData get() = _selectedMarket + private val _errMsg = MutableLiveData() + val errMsg: LiveData get() = _errMsg + + init { + _tickers.value = mutableListOf() + _selectedMarket.value = firstMarketName + } + + private fun onError(t: Throwable) { + _errMsg.value = t + } + + private fun onTickersCombine( + upbitTickers: List, + bithumbTickers: List, + coinOneTickers: List + ) { + onTickersLoaded( + TickerFormatter.combine( + upbitTickers, + bithumbTickers, + coinOneTickers + ) + ) + } + + private fun onTickersLoaded(tickers: List) { + _tickers.value = TickerFormatter.convertTo(tickers) + } + + fun selectedMarket(marketLike: String) { + _selectedMarket.value = marketLike + showTickers(marketLike) + } + + fun showTickers(marketLike: String?) { + viewModelScope.launch { + val upbitMarket = getUpbitMarketUseCase() + val strUpbitMarket = upbitMarket.filter { + it.market.startsWith(marketLike ?: "KRW") + }.joinToString { it.market } + val upbitTickers = async { getUpbitTickersUseCase(strUpbitMarket) } + + val bithumbTickers = async { getBithumbTickersUseCase() } + + val coinOneTickers = async { getCoinOneTickersUseCase() } + + onTickersCombine( + upbitTickers.await().toPresentation(), + bithumbTickers.await().toPresentation(), + coinOneTickers.await().toPresentation() + ) + } + } +} \ No newline at end of file diff --git a/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/presentation/util/ClickAdapter.kt b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/presentation/util/ClickAdapter.kt new file mode 100644 index 0000000..c7ab388 --- /dev/null +++ b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/presentation/util/ClickAdapter.kt @@ -0,0 +1,25 @@ +package sample.nackun.com.studyfirst.presentation.util + +import androidx.annotation.LayoutRes +import androidx.databinding.ViewDataBinding +import io.reactivex.subjects.PublishSubject +import sample.nackun.com.studyfirst.presentation.base.BaseRecyclerView + +open class ClickAdapter( + @LayoutRes private val layoutRes: Int, + bindingVariabledId: Int +) : BaseRecyclerView.BaseAdapter( + layoutRes, + bindingVariabledId +) { + private val onItemClickSubject = PublishSubject.create() + + fun getOnItemClickObservable() = onItemClickSubject + + override fun onBindViewHolder(baseViewHolder: BaseRecyclerView.BaseViewHolder, position: Int) { + items[position].let(baseViewHolder::bind) + baseViewHolder.itemView.setOnClickListener { it -> + onItemClickSubject.onNext(baseViewHolder.adapterPosition) + } + } +} \ No newline at end of file diff --git a/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/presentation/util/TickerFormatter.kt b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/presentation/util/TickerFormatter.kt new file mode 100644 index 0000000..420a858 --- /dev/null +++ b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/presentation/util/TickerFormatter.kt @@ -0,0 +1,137 @@ +package sample.nackun.com.studyfirst.presentation.util + +import android.annotation.SuppressLint +import android.graphics.Color +import sample.nackun.com.studyfirst.presentation.model.Ticker + +object TickerFormatter { + + @SuppressLint("DefaultLocale") + fun combine( + upbitTickers: List, + bithumbTickers: List, + coinOneTickers: List + ): List { + val combineList = mutableListOf() + combineList.clear() + + val markets = mutableListOf() + + upbitTickers.forEach { + markets.add(it.market) + } + bithumbTickers.forEach { + if (!markets.contains(it.market)) { + markets.add(it.market) + } + } + coinOneTickers.forEach { + if (!markets.contains(it.market)) { + markets.add(it.market) + } + } + + val emptyTicker = Ticker( + 0.0, + 0.0, + "", + 0.0, + 0.0, + 0 + ) + + markets.forEach { market -> + val upbitTicker = upbitTickers.find { + it.market.equals(market) + } ?: emptyTicker + + val bithumbTicker = bithumbTickers.find { + it.market.equals(market) + } ?: emptyTicker + + val coinOneTicker = coinOneTickers.find { + it.market.equals(market) + } ?: emptyTicker + + val upbitTickerAccTradePrice24h = upbitTicker.accTradePrice24h + val bithumbTickerAccTradePrice24h = bithumbTicker.accTradePrice24h + val coinOneTickerAccTradePrice24h = coinOneTicker.accTradePrice24h + + if (upbitTickerAccTradePrice24h > bithumbTickerAccTradePrice24h) { + if (upbitTickerAccTradePrice24h > coinOneTickerAccTradePrice24h) { + combineList.add(upbitTicker) + } else { + combineList.add(coinOneTicker) + } + } else { + if (bithumbTickerAccTradePrice24h > coinOneTickerAccTradePrice24h) { + combineList.add(bithumbTicker) + } else { + combineList.add(coinOneTicker) + } + } + } + + return combineList + } + + fun convertTo(target: List): List> { + val convertList = mutableListOf>() + convertList.clear() + + target.forEachIndexed { index, ticker -> + convertList.add( + index, + hashMapOf( + "tickerName" to getTickerName(ticker.market), + "currentPrice" to getCurrentPrice(ticker.tradePrice), + "comparePrice" to getComparePrice(ticker.tradePrice, ticker.prevClosingPrice), + "compareColor" to getCompareColor(ticker.tradePrice, ticker.prevClosingPrice), + "changePrice" to getChangePrice(ticker.accTradePrice24h), + "exchangeImg" to getMarketImgSrc(ticker.exchangeImg) + ) + ) + } + return convertList + } + + private fun getMarketImgSrc(exchangeImg: Int) = + exchangeImg.toString() + + private fun getTickerName(tickerName: String) = + tickerName.substring(tickerName.indexOf("-") + 1, tickerName.length) + + private fun getCurrentPrice(currentPrice: Double): String { + return when { + currentPrice > 10 -> String.format("%,d", currentPrice.toInt()) + currentPrice > 1 -> String.format("%,.2f", currentPrice) + currentPrice < 1 -> String.format("%,.8f", currentPrice) + else -> String.format("%,d", currentPrice.toInt()) + } + } + + private fun getComparePrice(currentPrice: Double, beforePrice: Double) = + String.format("%.2f", ((currentPrice - beforePrice) / beforePrice * 100)) + "%" + + private fun getCompareColor(currentPrice: Double, beforePrice: Double): String { + val differPrice = (currentPrice - beforePrice) / beforePrice * 100 + return when { + differPrice > 0 -> Color.RED.toString() + differPrice < 0 -> Color.BLUE.toString() + else -> Color.BLACK.toString() + } + } + + private fun getChangePrice(changePrice: Double): String { + return when { + changePrice / 1_000_000 > 50 -> + String.format("%,d", (changePrice / 1_000_000).toInt()) + " M" + changePrice / 1_000 > 1_000 -> + String.format("%,d", (changePrice / 1_000).toInt()) + " K" + changePrice > 1_000 -> + String.format("%,d", changePrice.toInt()) + else -> + String.format("%,.3f", changePrice) + } + } +} \ No newline at end of file diff --git a/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/presentation/util/TickersExt.kt b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/presentation/util/TickersExt.kt new file mode 100644 index 0000000..895c702 --- /dev/null +++ b/StudyFirst/app/src/main/java/sample/nackun/com/studyfirst/presentation/util/TickersExt.kt @@ -0,0 +1,15 @@ +package sample.nackun.com.studyfirst.presentation.util + +import sample.nackun.com.studyfirst.domain.entity.Ticker + +fun List.toPresentation(): List = + this.map { + sample.nackun.com.studyfirst.presentation.model.Ticker( + it.accTradePrice24h, + it.changePrice, + it.market, + it.prevClosingPrice, + it.tradePrice, + it.exchangeImg + ) + } \ No newline at end of file diff --git a/StudyFirst/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/StudyFirst/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 0000000..6348baa --- /dev/null +++ b/StudyFirst/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + diff --git a/StudyFirst/app/src/main/res/drawable/bithumb_img.png b/StudyFirst/app/src/main/res/drawable/bithumb_img.png new file mode 100644 index 0000000..bd7f3bc Binary files /dev/null and b/StudyFirst/app/src/main/res/drawable/bithumb_img.png differ diff --git a/StudyFirst/app/src/main/res/drawable/coinone_img.png b/StudyFirst/app/src/main/res/drawable/coinone_img.png new file mode 100644 index 0000000..cace9a4 Binary files /dev/null and b/StudyFirst/app/src/main/res/drawable/coinone_img.png differ diff --git a/StudyFirst/app/src/main/res/drawable/ic_launcher_background.xml b/StudyFirst/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..a0ad202 --- /dev/null +++ b/StudyFirst/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/StudyFirst/app/src/main/res/drawable/rounded.xml b/StudyFirst/app/src/main/res/drawable/rounded.xml new file mode 100644 index 0000000..3878770 --- /dev/null +++ b/StudyFirst/app/src/main/res/drawable/rounded.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/StudyFirst/app/src/main/res/drawable/upbit_img.png b/StudyFirst/app/src/main/res/drawable/upbit_img.png new file mode 100644 index 0000000..e1f8846 Binary files /dev/null and b/StudyFirst/app/src/main/res/drawable/upbit_img.png differ diff --git a/StudyFirst/app/src/main/res/layout/activity_detail.xml b/StudyFirst/app/src/main/res/layout/activity_detail.xml new file mode 100644 index 0000000..e39aa25 --- /dev/null +++ b/StudyFirst/app/src/main/res/layout/activity_detail.xml @@ -0,0 +1,14 @@ + + + + \ No newline at end of file diff --git a/StudyFirst/app/src/main/res/layout/activity_ticker.xml b/StudyFirst/app/src/main/res/layout/activity_ticker.xml new file mode 100644 index 0000000..b401850 --- /dev/null +++ b/StudyFirst/app/src/main/res/layout/activity_ticker.xml @@ -0,0 +1,14 @@ + + + + \ No newline at end of file diff --git a/StudyFirst/app/src/main/res/layout/detail_fragment.xml b/StudyFirst/app/src/main/res/layout/detail_fragment.xml new file mode 100644 index 0000000..cb4bbb8 --- /dev/null +++ b/StudyFirst/app/src/main/res/layout/detail_fragment.xml @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/StudyFirst/app/src/main/res/layout/ticker_fragment.xml b/StudyFirst/app/src/main/res/layout/ticker_fragment.xml new file mode 100644 index 0000000..436d621 --- /dev/null +++ b/StudyFirst/app/src/main/res/layout/ticker_fragment.xml @@ -0,0 +1,109 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/StudyFirst/app/src/main/res/layout/ticker_item.xml b/StudyFirst/app/src/main/res/layout/ticker_item.xml new file mode 100644 index 0000000..429e988 --- /dev/null +++ b/StudyFirst/app/src/main/res/layout/ticker_item.xml @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/StudyFirst/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/StudyFirst/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000..bbd3e02 --- /dev/null +++ b/StudyFirst/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/StudyFirst/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/StudyFirst/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 0000000..bbd3e02 --- /dev/null +++ b/StudyFirst/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/StudyFirst/app/src/main/res/mipmap-hdpi/ic_launcher.png b/StudyFirst/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000..898f3ed Binary files /dev/null and b/StudyFirst/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/StudyFirst/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/StudyFirst/app/src/main/res/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 0000000..dffca36 Binary files /dev/null and b/StudyFirst/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ diff --git a/StudyFirst/app/src/main/res/mipmap-mdpi/ic_launcher.png b/StudyFirst/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000..64ba76f Binary files /dev/null and b/StudyFirst/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/StudyFirst/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/StudyFirst/app/src/main/res/mipmap-mdpi/ic_launcher_round.png new file mode 100644 index 0000000..dae5e08 Binary files /dev/null and b/StudyFirst/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ diff --git a/StudyFirst/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/StudyFirst/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000..e5ed465 Binary files /dev/null and b/StudyFirst/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/StudyFirst/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/StudyFirst/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 0000000..14ed0af Binary files /dev/null and b/StudyFirst/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/StudyFirst/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/StudyFirst/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000..b0907ca Binary files /dev/null and b/StudyFirst/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/StudyFirst/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/StudyFirst/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 0000000..d8ae031 Binary files /dev/null and b/StudyFirst/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/StudyFirst/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/StudyFirst/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000..2c18de9 Binary files /dev/null and b/StudyFirst/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/StudyFirst/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/StudyFirst/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 0000000..beed3cd Binary files /dev/null and b/StudyFirst/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/StudyFirst/app/src/main/res/values/colors.xml b/StudyFirst/app/src/main/res/values/colors.xml new file mode 100644 index 0000000..0907caa --- /dev/null +++ b/StudyFirst/app/src/main/res/values/colors.xml @@ -0,0 +1,8 @@ + + + #008577 + #00574B + #D81B60 + #384786 + #bebbb4 + diff --git a/StudyFirst/app/src/main/res/values/strings.xml b/StudyFirst/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..447ea85 --- /dev/null +++ b/StudyFirst/app/src/main/res/values/strings.xml @@ -0,0 +1,11 @@ + + StudyFirst + 업비트(Upbit) + KRW + BTC + USDT + 코인명 + 현재가 + 전일대비 + 거래대금 + diff --git a/StudyFirst/app/src/main/res/values/styles.xml b/StudyFirst/app/src/main/res/values/styles.xml new file mode 100644 index 0000000..d554a3c --- /dev/null +++ b/StudyFirst/app/src/main/res/values/styles.xml @@ -0,0 +1,13 @@ + + + + + + diff --git a/StudyFirst/app/src/test/java/sample/nackun/com/studyfirst/ExampleUnitTest.kt b/StudyFirst/app/src/test/java/sample/nackun/com/studyfirst/ExampleUnitTest.kt new file mode 100644 index 0000000..402f965 --- /dev/null +++ b/StudyFirst/app/src/test/java/sample/nackun/com/studyfirst/ExampleUnitTest.kt @@ -0,0 +1,14 @@ +package sample.nackun.com.studyfirst + +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() { + } +} diff --git a/StudyFirst/build.gradle b/StudyFirst/build.gradle new file mode 100644 index 0000000..d906020 --- /dev/null +++ b/StudyFirst/build.gradle @@ -0,0 +1,27 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. + +buildscript { + ext.kotlin_version = '1.3.31' + repositories { + google() + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:3.6.0-alpha03' + 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/StudyFirst/gradle.properties b/StudyFirst/gradle.properties new file mode 100644 index 0000000..3d8ce0c --- /dev/null +++ b/StudyFirst/gradle.properties @@ -0,0 +1,17 @@ +# 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 +# Kotlin code style for this project: "official" or "obsolete": +kotlin.code.style=official +android.useAndroidX=true +android.enableJetifier=true diff --git a/StudyFirst/gradle/wrapper/gradle-wrapper.properties b/StudyFirst/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..2d74638 --- /dev/null +++ b/StudyFirst/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Sat Jun 08 19:23:27 KST 2019 +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/StudyFirst/gradlew b/StudyFirst/gradlew new file mode 100644 index 0000000..cccdd3d --- /dev/null +++ b/StudyFirst/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/StudyFirst/gradlew.bat b/StudyFirst/gradlew.bat new file mode 100644 index 0000000..f955316 --- /dev/null +++ b/StudyFirst/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/StudyFirst/settings.gradle b/StudyFirst/settings.gradle new file mode 100644 index 0000000..e7b4def --- /dev/null +++ b/StudyFirst/settings.gradle @@ -0,0 +1 @@ +include ':app'