From d48259782856b8f8d6ad1eb7f0bdcb85dd564df0 Mon Sep 17 00:00:00 2001 From: handnew Date: Wed, 13 Jul 2022 00:55:31 +0900 Subject: [PATCH] =?UTF-8?q?10=EC=A3=BC=EC=B0=A8=20=EA=B3=BC=EC=A0=9C=20?= =?UTF-8?q?=EB=A1=9C=EA=B7=B8=EC=9D=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Homework/Handnew04/RxStudy/app/build.gradle | 15 ++++ .../RxStudy/app/src/main/AndroidManifest.xml | 54 ++++++++------- .../observerpattern/DefaultObserver.kt | 2 +- .../observerpattern/DefaultSubject.kt | 2 +- .../ui/ObserverPatternActivity.kt | 4 +- .../observerpattern/ui/PercentEditText.kt | 4 +- .../observerpattern/ui/PercentSeekBar.kt | 4 +- .../observerpattern/ui/PercentTextView.kt | 4 +- .../java/com/example/rxstudy/MainActivity.kt | 11 ++- .../java/com/example/rxstudy/RxApplication.kt | 18 +++++ .../com/example/rxstudy/login/PrefUtil.kt | 21 ++++++ .../rxstudy/login/data/local/AppDatabase.kt | 11 +++ .../login/data/local/DatabaseClient.kt | 19 ++++++ .../login/data/local/token/LocalTokenDao.kt | 28 ++++++++ .../data/local/token/LocalTokenDataSource.kt | 13 ++++ .../local/token/LocalTokenDataSourceImpl.kt | 40 +++++++++++ .../login/data/local/token/LocalTokenItem.kt | 12 ++++ .../data/local/token/LocalTokenMapper.kt | 12 ++++ .../login/data/remote/RetrofitClient.kt | 36 ++++++++++ .../data/remote/base/BaseAPICallResult.kt | 6 ++ .../remote/base/BaseAPICallTransformer.kt | 17 +++++ .../login/data/remote/base/BaseCallback.kt | 6 ++ .../login/data/remote/login/LoginApi.kt | 14 ++++ .../data/remote/login/LoginDataSource.kt | 9 +++ .../data/remote/login/LoginDataSourceImpl.kt | 19 ++++++ .../login/data/remote/login/LoginInfo.kt | 6 ++ .../login/data/remote/login/LoginItem.kt | 6 ++ .../data/repository/login/LoginRepository.kt | 9 +++ .../repository/login/LoginRepositoryImpl.kt | 55 +++++++++++++++ .../rxstudy/login/ui/LoginExampleActivity.kt | 68 +++++++++++++++++++ .../rxstudy/login/ui/LoginViewModel.kt | 37 ++++++++++ .../res/layout/activity_example_login.xml | 40 +++++++++++ .../app/src/main/res/layout/activity_main.xml | 7 +- .../res/layout/activity_pattern_observer.xml | 6 +- 34 files changed, 574 insertions(+), 41 deletions(-) rename Homework/Handnew04/RxStudy/app/src/main/java/com/example/{rxstudy => }/observerpattern/DefaultObserver.kt (61%) rename Homework/Handnew04/RxStudy/app/src/main/java/com/example/{rxstudy => }/observerpattern/DefaultSubject.kt (94%) rename Homework/Handnew04/RxStudy/app/src/main/java/com/example/{rxstudy => }/observerpattern/ui/ObserverPatternActivity.kt (81%) rename Homework/Handnew04/RxStudy/app/src/main/java/com/example/{rxstudy => }/observerpattern/ui/PercentEditText.kt (91%) rename Homework/Handnew04/RxStudy/app/src/main/java/com/example/{rxstudy => }/observerpattern/ui/PercentSeekBar.kt (90%) rename Homework/Handnew04/RxStudy/app/src/main/java/com/example/{rxstudy => }/observerpattern/ui/PercentTextView.kt (86%) create mode 100644 Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/RxApplication.kt create mode 100644 Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/PrefUtil.kt create mode 100644 Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/local/AppDatabase.kt create mode 100644 Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/local/DatabaseClient.kt create mode 100644 Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/local/token/LocalTokenDao.kt create mode 100644 Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/local/token/LocalTokenDataSource.kt create mode 100644 Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/local/token/LocalTokenDataSourceImpl.kt create mode 100644 Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/local/token/LocalTokenItem.kt create mode 100644 Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/local/token/LocalTokenMapper.kt create mode 100644 Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/remote/RetrofitClient.kt create mode 100644 Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/remote/base/BaseAPICallResult.kt create mode 100644 Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/remote/base/BaseAPICallTransformer.kt create mode 100644 Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/remote/base/BaseCallback.kt create mode 100644 Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/remote/login/LoginApi.kt create mode 100644 Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/remote/login/LoginDataSource.kt create mode 100644 Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/remote/login/LoginDataSourceImpl.kt create mode 100644 Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/remote/login/LoginInfo.kt create mode 100644 Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/remote/login/LoginItem.kt create mode 100644 Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/repository/login/LoginRepository.kt create mode 100644 Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/repository/login/LoginRepositoryImpl.kt create mode 100644 Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/ui/LoginExampleActivity.kt create mode 100644 Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/ui/LoginViewModel.kt create mode 100644 Homework/Handnew04/RxStudy/app/src/main/res/layout/activity_example_login.xml diff --git a/Homework/Handnew04/RxStudy/app/build.gradle b/Homework/Handnew04/RxStudy/app/build.gradle index 54d6ebf..317e78d 100644 --- a/Homework/Handnew04/RxStudy/app/build.gradle +++ b/Homework/Handnew04/RxStudy/app/build.gradle @@ -16,6 +16,8 @@ android { versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + + buildConfigField("String", "BASE_URL", '"https://r5670326j8.execute-api.ap-northeast-2.amazonaws.com/delivery_server/"') } buildTypes { @@ -43,7 +45,20 @@ dependencies { implementation 'androidx.appcompat:appcompat:1.4.1' implementation 'com.google.android.material:material:1.5.0' implementation 'androidx.constraintlayout:constraintlayout:2.1.3' + //rxJava implementation 'com.jakewharton.rxbinding3:rxbinding:3.1.0' + //retrofit2 + implementation 'com.squareup.retrofit2:retrofit:2.9.0' + implementation 'com.squareup.retrofit2:adapter-rxjava2:2.9.0' + implementation 'com.squareup.retrofit2:converter-gson:2.9.0' + //okHttp + implementation 'com.squareup.okhttp3:okhttp:4.9.1' + implementation 'com.squareup.okhttp3:logging-interceptor:4.9.1' + //room + implementation 'androidx.room:room-runtime:2.4.2' + implementation 'androidx.room:room-ktx:2.4.2' + implementation 'androidx.room:room-rxjava2:2.4.2' + kapt 'androidx.room:room-compiler:2.4.2' testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.3' diff --git a/Homework/Handnew04/RxStudy/app/src/main/AndroidManifest.xml b/Homework/Handnew04/RxStudy/app/src/main/AndroidManifest.xml index ed7bb70..a8b9128 100644 --- a/Homework/Handnew04/RxStudy/app/src/main/AndroidManifest.xml +++ b/Homework/Handnew04/RxStudy/app/src/main/AndroidManifest.xml @@ -1,31 +1,35 @@ + xmlns:tools="http://schemas.android.com/tools" + package="com.example.rxstudy"> - - - - + - - - - - - - - + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/observerpattern/DefaultObserver.kt b/Homework/Handnew04/RxStudy/app/src/main/java/com/example/observerpattern/DefaultObserver.kt similarity index 61% rename from Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/observerpattern/DefaultObserver.kt rename to Homework/Handnew04/RxStudy/app/src/main/java/com/example/observerpattern/DefaultObserver.kt index 909e784..b06502a 100644 --- a/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/observerpattern/DefaultObserver.kt +++ b/Homework/Handnew04/RxStudy/app/src/main/java/com/example/observerpattern/DefaultObserver.kt @@ -1,4 +1,4 @@ -package com.example.rxstudy.observerpattern +package com.example.observerpattern interface DefaultObserver { fun notifyDataIsArrived(value : T) diff --git a/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/observerpattern/DefaultSubject.kt b/Homework/Handnew04/RxStudy/app/src/main/java/com/example/observerpattern/DefaultSubject.kt similarity index 94% rename from Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/observerpattern/DefaultSubject.kt rename to Homework/Handnew04/RxStudy/app/src/main/java/com/example/observerpattern/DefaultSubject.kt index a5d1bdc..cc45164 100644 --- a/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/observerpattern/DefaultSubject.kt +++ b/Homework/Handnew04/RxStudy/app/src/main/java/com/example/observerpattern/DefaultSubject.kt @@ -1,4 +1,4 @@ -package com.example.rxstudy.observerpattern +package com.example.observerpattern import java.util.ArrayList diff --git a/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/observerpattern/ui/ObserverPatternActivity.kt b/Homework/Handnew04/RxStudy/app/src/main/java/com/example/observerpattern/ui/ObserverPatternActivity.kt similarity index 81% rename from Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/observerpattern/ui/ObserverPatternActivity.kt rename to Homework/Handnew04/RxStudy/app/src/main/java/com/example/observerpattern/ui/ObserverPatternActivity.kt index f690320..9102e24 100644 --- a/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/observerpattern/ui/ObserverPatternActivity.kt +++ b/Homework/Handnew04/RxStudy/app/src/main/java/com/example/observerpattern/ui/ObserverPatternActivity.kt @@ -1,9 +1,9 @@ -package com.example.rxstudy.observerpattern.ui +package com.example.observerpattern.ui import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import com.example.rxstudy.R -import com.example.rxstudy.observerpattern.DefaultSubject +import com.example.observerpattern.DefaultSubject class ObserverPatternActivity : AppCompatActivity() { companion object { diff --git a/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/observerpattern/ui/PercentEditText.kt b/Homework/Handnew04/RxStudy/app/src/main/java/com/example/observerpattern/ui/PercentEditText.kt similarity index 91% rename from Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/observerpattern/ui/PercentEditText.kt rename to Homework/Handnew04/RxStudy/app/src/main/java/com/example/observerpattern/ui/PercentEditText.kt index 7969543..98e9fdc 100644 --- a/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/observerpattern/ui/PercentEditText.kt +++ b/Homework/Handnew04/RxStudy/app/src/main/java/com/example/observerpattern/ui/PercentEditText.kt @@ -1,10 +1,10 @@ -package com.example.rxstudy.observerpattern.ui +package com.example.observerpattern.ui import android.content.Context import android.util.AttributeSet import androidx.appcompat.widget.AppCompatEditText import androidx.core.widget.doAfterTextChanged -import com.example.rxstudy.observerpattern.DefaultObserver +import com.example.observerpattern.DefaultObserver class PercentEditText : AppCompatEditText, DefaultObserver { constructor(context: Context) : super(context) diff --git a/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/observerpattern/ui/PercentSeekBar.kt b/Homework/Handnew04/RxStudy/app/src/main/java/com/example/observerpattern/ui/PercentSeekBar.kt similarity index 90% rename from Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/observerpattern/ui/PercentSeekBar.kt rename to Homework/Handnew04/RxStudy/app/src/main/java/com/example/observerpattern/ui/PercentSeekBar.kt index f96f726..e52a682 100644 --- a/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/observerpattern/ui/PercentSeekBar.kt +++ b/Homework/Handnew04/RxStudy/app/src/main/java/com/example/observerpattern/ui/PercentSeekBar.kt @@ -1,10 +1,10 @@ -package com.example.rxstudy.observerpattern.ui +package com.example.observerpattern.ui import android.content.Context import android.util.AttributeSet import android.widget.SeekBar import androidx.appcompat.widget.AppCompatSeekBar -import com.example.rxstudy.observerpattern.DefaultObserver +import com.example.observerpattern.DefaultObserver class PercentSeekBar : AppCompatSeekBar, DefaultObserver { constructor(context: Context) : super(context) diff --git a/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/observerpattern/ui/PercentTextView.kt b/Homework/Handnew04/RxStudy/app/src/main/java/com/example/observerpattern/ui/PercentTextView.kt similarity index 86% rename from Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/observerpattern/ui/PercentTextView.kt rename to Homework/Handnew04/RxStudy/app/src/main/java/com/example/observerpattern/ui/PercentTextView.kt index e5480c0..67f7d45 100644 --- a/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/observerpattern/ui/PercentTextView.kt +++ b/Homework/Handnew04/RxStudy/app/src/main/java/com/example/observerpattern/ui/PercentTextView.kt @@ -1,10 +1,10 @@ -package com.example.rxstudy.observerpattern.ui +package com.example.observerpattern.ui import android.annotation.SuppressLint import android.content.Context import android.util.AttributeSet import androidx.appcompat.widget.AppCompatTextView -import com.example.rxstudy.observerpattern.DefaultObserver +import com.example.observerpattern.DefaultObserver class PercentTextView : AppCompatTextView, DefaultObserver { constructor(context: Context) : super(context) diff --git a/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/MainActivity.kt b/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/MainActivity.kt index 71f2fa5..6a5038c 100644 --- a/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/MainActivity.kt +++ b/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/MainActivity.kt @@ -1,10 +1,11 @@ package com.example.rxstudy import android.content.Intent -import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import android.widget.Button -import com.example.rxstudy.observerpattern.ui.ObserverPatternActivity +import androidx.appcompat.app.AppCompatActivity +import com.example.observerpattern.ui.ObserverPatternActivity +import com.example.rxstudy.login.ui.LoginExampleActivity import com.example.rxstudy.operator.FlowControlOperatorSampleActivity import com.example.rxstudy.rxbinding.RxBindingSampleActivity import com.example.rxstudy.scheduler.SchedulerSampleActivity @@ -14,6 +15,7 @@ class MainActivity : AppCompatActivity() { private lateinit var schedulerSampleButton: Button private lateinit var flowOperatorButton: Button private lateinit var rxBindingSampleButton: Button + private val loginExampleButton: Button by lazy { findViewById(R.id.bt_login_example) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -47,5 +49,10 @@ class MainActivity : AppCompatActivity() { val intent = Intent(this@MainActivity, RxBindingSampleActivity::class.java) startActivity(intent) } + + loginExampleButton.setOnClickListener { + val intent = Intent(this@MainActivity, LoginExampleActivity::class.java) + startActivity(intent) + } } } \ No newline at end of file diff --git a/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/RxApplication.kt b/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/RxApplication.kt new file mode 100644 index 0000000..2763fee --- /dev/null +++ b/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/RxApplication.kt @@ -0,0 +1,18 @@ +package com.example.rxstudy + +import android.app.Application +import com.example.rxstudy.login.data.local.DatabaseClient +import io.reactivex.exceptions.UndeliverableException +import io.reactivex.plugins.RxJavaPlugins + +class RxApplication: Application() { + override fun onCreate() { + super.onCreate() + RxJavaPlugins.setErrorHandler { e: Throwable -> + if (e is UndeliverableException) { + return@setErrorHandler + } + } + DatabaseClient.createDatabase(this) + } +} \ No newline at end of file diff --git a/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/PrefUtil.kt b/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/PrefUtil.kt new file mode 100644 index 0000000..ec8bf9b --- /dev/null +++ b/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/PrefUtil.kt @@ -0,0 +1,21 @@ +package com.example.rxstudy.login + +import android.content.Context +import android.content.Context.MODE_PRIVATE + +class PrefUtil(context: Context) { + companion object { + const val DEFAULT_VALUE = "" + const val PREF_DEFAULT = "PREF_DEFAULT" + const val ACCESS_TOKEN = "LOGIN_TOKEN" + } + + private val sharedPref = context.getSharedPreferences(PREF_DEFAULT, MODE_PRIVATE) + private fun getEdit() = sharedPref.edit() + + fun saveToken(token: String) { + getEdit().putString(ACCESS_TOKEN, token).apply() + } + + fun getToken() = sharedPref.getString(ACCESS_TOKEN, DEFAULT_VALUE) +} diff --git a/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/local/AppDatabase.kt b/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/local/AppDatabase.kt new file mode 100644 index 0000000..110df70 --- /dev/null +++ b/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/local/AppDatabase.kt @@ -0,0 +1,11 @@ +package com.example.rxstudy.login.data.local + +import androidx.room.Database +import androidx.room.RoomDatabase +import com.example.rxstudy.login.data.local.token.LocalTokenDao +import com.example.rxstudy.login.data.local.token.LocalTokenItem + +@Database(entities = [LocalTokenItem::class], version = 1) +abstract class AppDatabase: RoomDatabase() { + abstract fun localTokenDao(): LocalTokenDao +} \ No newline at end of file diff --git a/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/local/DatabaseClient.kt b/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/local/DatabaseClient.kt new file mode 100644 index 0000000..5d5af25 --- /dev/null +++ b/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/local/DatabaseClient.kt @@ -0,0 +1,19 @@ +package com.example.rxstudy.login.data.local + +import android.content.Context +import androidx.room.Room +import com.example.rxstudy.login.data.local.token.LocalTokenDao + +object DatabaseClient { + private lateinit var appDatabase: AppDatabase + + fun createDatabase(context: Context) { + appDatabase = Room.databaseBuilder( + context.applicationContext, + AppDatabase::class.java, + "database" + ).build() + } + + fun tokenDao(): LocalTokenDao = appDatabase.localTokenDao() +} \ No newline at end of file diff --git a/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/local/token/LocalTokenDao.kt b/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/local/token/LocalTokenDao.kt new file mode 100644 index 0000000..403407a --- /dev/null +++ b/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/local/token/LocalTokenDao.kt @@ -0,0 +1,28 @@ +package com.example.rxstudy.login.data.local.token + +import androidx.room.Dao +import androidx.room.Insert +import androidx.room.Query +import io.reactivex.Completable +import io.reactivex.Single + +@Dao +interface LocalTokenDao { + @Query(value = "SELECT * FROM token LIMIT 1") + fun getToken(): Single + + @Insert + fun saveToken(tokenItem: LocalTokenItem): Completable + + @Query(value = "DELETE FROM token") + fun deleteAllCachedToken(): Completable + + @Query(value = "SELECT * FROM token LIMIT 1") + fun getTokenNotRx(): LocalTokenItem + + @Insert + fun saveTokenNotRx(tokenItem: LocalTokenItem) + + @Query(value = "DELETE FROM token") + fun deleteAllCachedTokenNotRx() +} \ No newline at end of file diff --git a/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/local/token/LocalTokenDataSource.kt b/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/local/token/LocalTokenDataSource.kt new file mode 100644 index 0000000..d2472f9 --- /dev/null +++ b/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/local/token/LocalTokenDataSource.kt @@ -0,0 +1,13 @@ +package com.example.rxstudy.login.data.local.token + +import io.reactivex.Completable +import io.reactivex.Single + +interface LocalTokenDataSource { + fun getToken(): Single + fun saveToken(tokenItem: LocalTokenItem): Completable + fun deleteAllCachedToken(): Completable + fun getTokenNotRx(): LocalTokenItem + fun saveTokenNotRx(tokenItem: LocalTokenItem) + fun deleteAllCachedTokenNotRx() +} \ No newline at end of file diff --git a/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/local/token/LocalTokenDataSourceImpl.kt b/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/local/token/LocalTokenDataSourceImpl.kt new file mode 100644 index 0000000..ce525cd --- /dev/null +++ b/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/local/token/LocalTokenDataSourceImpl.kt @@ -0,0 +1,40 @@ +package com.example.rxstudy.login.data.local.token + +import io.reactivex.Completable +import io.reactivex.Single +import io.reactivex.schedulers.Schedulers + +class LocalTokenDataSourceImpl(private val localTokenDao: LocalTokenDao) : LocalTokenDataSource { + override fun getToken(): Single { + return localTokenDao + .getToken() + .subscribeOn(Schedulers.io()) + } + + override fun saveToken(tokenItem: LocalTokenItem): Completable { + return localTokenDao + .saveToken(tokenItem) + .subscribeOn(Schedulers.io()) + } + + override fun deleteAllCachedToken(): Completable { + return localTokenDao + .deleteAllCachedToken() + .subscribeOn(Schedulers.io()) + } + + override fun getTokenNotRx(): LocalTokenItem { + return localTokenDao + .getTokenNotRx() + } + + override fun saveTokenNotRx(tokenItem: LocalTokenItem) { + return localTokenDao + .saveTokenNotRx(tokenItem) + } + + override fun deleteAllCachedTokenNotRx() { + return localTokenDao + .deleteAllCachedTokenNotRx() + } +} \ No newline at end of file diff --git a/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/local/token/LocalTokenItem.kt b/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/local/token/LocalTokenItem.kt new file mode 100644 index 0000000..c68ca20 --- /dev/null +++ b/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/local/token/LocalTokenItem.kt @@ -0,0 +1,12 @@ +package com.example.rxstudy.login.data.local.token + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.PrimaryKey + +@Entity(tableName = "token") +data class LocalTokenItem( + @PrimaryKey(autoGenerate = true) val idx: Int = 0, + @ColumnInfo(name = "accessToken") val accessToken: String, + @ColumnInfo(name = "refreshToken") val refreshToken: String +) \ No newline at end of file diff --git a/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/local/token/LocalTokenMapper.kt b/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/local/token/LocalTokenMapper.kt new file mode 100644 index 0000000..17c8de3 --- /dev/null +++ b/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/local/token/LocalTokenMapper.kt @@ -0,0 +1,12 @@ +package com.example.rxstudy.login.data.local.token + +import com.example.rxstudy.login.data.remote.login.LoginItem + +object LocalTokenMapper { + fun mappingRemoteDataToLocal(loginItem: LoginItem): LocalTokenItem { + return LocalTokenItem( + accessToken = loginItem.access, + refreshToken = loginItem.refresh + ) + } +} \ No newline at end of file diff --git a/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/remote/RetrofitClient.kt b/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/remote/RetrofitClient.kt new file mode 100644 index 0000000..4c16e12 --- /dev/null +++ b/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/remote/RetrofitClient.kt @@ -0,0 +1,36 @@ +package com.example.rxstudy.login.data.remote + +import com.example.rxstudy.BuildConfig +import com.example.rxstudy.login.data.remote.login.LoginApi +import okhttp3.OkHttpClient +import okhttp3.logging.HttpLoggingInterceptor +import retrofit2.Retrofit +import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory +import retrofit2.converter.gson.GsonConverterFactory + +object RetrofitClient { + private const val baseURL = BuildConfig.BASE_URL + + private val okHttpClient: OkHttpClient by lazy { + return@lazy OkHttpClient + .Builder() + .addInterceptor(HttpLoggingInterceptor().apply { + level = HttpLoggingInterceptor.Level.BODY + }) + .build() + } + + private val buildRetrofitClient: Retrofit by lazy { + return@lazy Retrofit + .Builder() + .baseUrl(baseURL) + .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) + .addConverterFactory(GsonConverterFactory.create()) + .client(okHttpClient) + .build() + } + + val loginApi: LoginApi by lazy { + return@lazy buildRetrofitClient.create(LoginApi::class.java) + } +} \ No newline at end of file diff --git a/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/remote/base/BaseAPICallResult.kt b/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/remote/base/BaseAPICallResult.kt new file mode 100644 index 0000000..ffa3fa0 --- /dev/null +++ b/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/remote/base/BaseAPICallResult.kt @@ -0,0 +1,6 @@ +package com.example.rxstudy.login.data.remote.base + +data class BaseAPICallResult( + val result: T? = null, + val throwable: Throwable? = null +) \ No newline at end of file diff --git a/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/remote/base/BaseAPICallTransformer.kt b/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/remote/base/BaseAPICallTransformer.kt new file mode 100644 index 0000000..3399f01 --- /dev/null +++ b/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/remote/base/BaseAPICallTransformer.kt @@ -0,0 +1,17 @@ +package com.example.rxstudy.login.data.remote.base + +import io.reactivex.Completable +import io.reactivex.Single +import io.reactivex.SingleTransformer + +fun Completable.transformCompletableToSingleDefault(): Single> = + toSingleDefault(Unit).compose(wrappingSingleAPIResultData()) + +fun Single.wrappingAPICallResult(): Single> = + compose(wrappingSingleAPIResultData()) + +fun wrappingSingleAPIResultData() = SingleTransformer> { single -> + single + .map { data -> BaseAPICallResult(result = data) } + .onErrorReturn { BaseAPICallResult(throwable = it) } +} \ No newline at end of file diff --git a/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/remote/base/BaseCallback.kt b/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/remote/base/BaseCallback.kt new file mode 100644 index 0000000..1b74c78 --- /dev/null +++ b/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/remote/base/BaseCallback.kt @@ -0,0 +1,6 @@ +package com.example.rxstudy.login.data.remote.base + +interface BaseCallback { + fun onSuccess(data: T) + fun onFail(throwable: Throwable) +} \ No newline at end of file diff --git a/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/remote/login/LoginApi.kt b/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/remote/login/LoginApi.kt new file mode 100644 index 0000000..a5926de --- /dev/null +++ b/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/remote/login/LoginApi.kt @@ -0,0 +1,14 @@ +package com.example.rxstudy.login.data.remote.login + +import io.reactivex.Single +import retrofit2.Call +import retrofit2.http.Body +import retrofit2.http.POST + +interface LoginApi { + @POST("api/token/") + fun loginRetrofitCall(@Body loginInfo: LoginInfo): Call + + @POST("api/token/") + fun loginRxStream(@Body loginInfo: LoginInfo): Single +} \ No newline at end of file diff --git a/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/remote/login/LoginDataSource.kt b/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/remote/login/LoginDataSource.kt new file mode 100644 index 0000000..0be629a --- /dev/null +++ b/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/remote/login/LoginDataSource.kt @@ -0,0 +1,9 @@ +package com.example.rxstudy.login.data.remote.login + +import io.reactivex.Single +import retrofit2.Callback + +interface LoginDataSource { + fun loginRetrofitCall(id: String, password: String, callback: Callback) + fun loginRxStream(id: String, password: String): Single +} \ No newline at end of file diff --git a/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/remote/login/LoginDataSourceImpl.kt b/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/remote/login/LoginDataSourceImpl.kt new file mode 100644 index 0000000..d06e427 --- /dev/null +++ b/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/remote/login/LoginDataSourceImpl.kt @@ -0,0 +1,19 @@ +package com.example.rxstudy.login.data.remote.login + +import io.reactivex.Single +import io.reactivex.schedulers.Schedulers +import retrofit2.Callback + +class LoginDataSourceImpl(private val loginApi: LoginApi) : LoginDataSource { + override fun loginRetrofitCall(id: String, password: String, callback: Callback) { + loginApi.loginRetrofitCall(LoginInfo(id, password)) + .enqueue(callback) + } + + override fun loginRxStream(id: String, password: String): Single { + return loginApi + .loginRxStream(LoginInfo(id, password)) + .subscribeOn(Schedulers.io()) + } + +} \ No newline at end of file diff --git a/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/remote/login/LoginInfo.kt b/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/remote/login/LoginInfo.kt new file mode 100644 index 0000000..d0ea919 --- /dev/null +++ b/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/remote/login/LoginInfo.kt @@ -0,0 +1,6 @@ +package com.example.rxstudy.login.data.remote.login + +data class LoginInfo( + val username: String, + val password: String +) \ No newline at end of file diff --git a/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/remote/login/LoginItem.kt b/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/remote/login/LoginItem.kt new file mode 100644 index 0000000..c1e461b --- /dev/null +++ b/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/remote/login/LoginItem.kt @@ -0,0 +1,6 @@ +package com.example.rxstudy.login.data.remote.login + +data class LoginItem( + val access: String, + val refresh: String +) \ No newline at end of file diff --git a/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/repository/login/LoginRepository.kt b/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/repository/login/LoginRepository.kt new file mode 100644 index 0000000..b231b4d --- /dev/null +++ b/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/repository/login/LoginRepository.kt @@ -0,0 +1,9 @@ +package com.example.rxstudy.login.data.repository.login + +import com.example.rxstudy.login.data.remote.base.BaseCallback +import io.reactivex.Completable + +interface LoginRepository { + fun loginRetrofitCall(id: String, password:String, callback: BaseCallback) + fun loginRxStream(id: String, password: String): Completable +} \ No newline at end of file diff --git a/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/repository/login/LoginRepositoryImpl.kt b/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/repository/login/LoginRepositoryImpl.kt new file mode 100644 index 0000000..4ac0913 --- /dev/null +++ b/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/data/repository/login/LoginRepositoryImpl.kt @@ -0,0 +1,55 @@ +package com.example.rxstudy.login.data.repository.login + +import com.example.rxstudy.login.data.local.token.LocalTokenDataSource +import com.example.rxstudy.login.data.local.token.LocalTokenMapper.mappingRemoteDataToLocal +import com.example.rxstudy.login.data.remote.base.BaseCallback +import com.example.rxstudy.login.data.remote.login.LoginDataSource +import com.example.rxstudy.login.data.remote.login.LoginItem +import io.reactivex.Completable +import retrofit2.Call +import retrofit2.Callback +import retrofit2.Response + +class LoginRepositoryImpl( + private val localTokenDataSource: LocalTokenDataSource, + private val loginDataSource: LoginDataSource +) : LoginRepository { + + override fun loginRetrofitCall(id: String, password: String, callback: BaseCallback) { + loginDataSource + .loginRetrofitCall(id, password, object : Callback { + override fun onResponse(call: Call, response: Response) { + if (response.isSuccessful) { + try { + Thread { + localTokenDataSource + .deleteAllCachedTokenNotRx() + localTokenDataSource + .saveTokenNotRx(mappingRemoteDataToLocal(response.body()!!)) + }.start() + } catch (e: Throwable) { + e.printStackTrace() + } + callback.onSuccess(Unit) + } else { + callback.onFail(Exception()) + } + } + + override fun onFailure(call: Call, t: Throwable) { + callback.onFail(t) + } + }) + } + + override fun loginRxStream(id: String, password: String): Completable { + return loginDataSource + .loginRxStream(id, password) + .flatMapCompletable { + localTokenDataSource + .deleteAllCachedToken() + .andThen(localTokenDataSource.saveToken(mappingRemoteDataToLocal(it))) + //.andThen(getFirebaseTokenSingle.ignoreElement()) + } + } +} \ No newline at end of file diff --git a/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/ui/LoginExampleActivity.kt b/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/ui/LoginExampleActivity.kt new file mode 100644 index 0000000..3e400d0 --- /dev/null +++ b/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/ui/LoginExampleActivity.kt @@ -0,0 +1,68 @@ +package com.example.rxstudy.login.ui + +import android.os.Bundle +import androidx.appcompat.app.AppCompatActivity +import com.example.rxstudy.databinding.ActivityExampleLoginBinding +import com.example.rxstudy.login.data.local.DatabaseClient +import com.example.rxstudy.login.data.local.token.LocalTokenDataSourceImpl +import com.example.rxstudy.login.data.remote.RetrofitClient +import com.example.rxstudy.login.data.remote.login.LoginDataSourceImpl +import com.example.rxstudy.login.data.repository.login.LoginRepositoryImpl +import com.jakewharton.rxbinding3.view.clicks +import com.jakewharton.rxbinding3.widget.textChanges +import io.reactivex.disposables.CompositeDisposable + +class LoginExampleActivity : AppCompatActivity() { + private val binding: ActivityExampleLoginBinding by lazy { + ActivityExampleLoginBinding.inflate(layoutInflater) + } + + private val compositeDisposable = CompositeDisposable() + + private val viewModel: LoginViewModel by lazy { + LoginViewModel( + loginRepository = LoginRepositoryImpl( + localTokenDataSource = LocalTokenDataSourceImpl( + localTokenDao = DatabaseClient.tokenDao() + ), loginDataSource = LoginDataSourceImpl( + loginApi = RetrofitClient.loginApi + ) + ) + ) + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(binding.root) + + setListener() + } + + private fun setListener() { + val idChanges = binding.etId.textChanges() + val passwordChanges = binding.etPw.textChanges() + + compositeDisposable.add( + binding.btLogin.clicks().subscribe({ + viewModel.loginRxStream( + binding.etId.text.toString(), binding.etPw.text.toString() + ) + }, {}) + ) + compositeDisposable.add( + viewModel.loginSuccessSubject.subscribe({ successToLogin -> + if (successToLogin) { + binding.tvResult.text = "로그인 성공" + } else { + binding.tvResult.text = "로그인 실패" + } + }, { it.printStackTrace() }) + ) + } + + override fun onDestroy() { + super.onDestroy() + viewModel.onViewCleared() + compositeDisposable.dispose() + } +} \ No newline at end of file diff --git a/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/ui/LoginViewModel.kt b/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/ui/LoginViewModel.kt new file mode 100644 index 0000000..604064f --- /dev/null +++ b/Homework/Handnew04/RxStudy/app/src/main/java/com/example/rxstudy/login/ui/LoginViewModel.kt @@ -0,0 +1,37 @@ +package com.example.rxstudy.login.ui + +import com.example.rxstudy.login.data.remote.base.BaseCallback +import com.example.rxstudy.login.data.remote.base.transformCompletableToSingleDefault +import com.example.rxstudy.login.data.repository.login.LoginRepository +import io.reactivex.disposables.CompositeDisposable +import io.reactivex.subjects.PublishSubject + +class LoginViewModel(private val loginRepository: LoginRepository) { + val loginSuccessSubject = PublishSubject.create() + + private val loginSubject = PublishSubject.create>() + private val compositeDisposable = CompositeDisposable() + + init { + compositeDisposable + .add( + loginSubject + .flatMapSingle { + loginRepository + .loginRxStream(it.first, it.second) + .transformCompletableToSingleDefault() + } + .subscribe( + { loginSuccessSubject.onNext(it.throwable == null) }, + { it.printStackTrace() }) + ) + } + + fun loginRxStream(id: String, password: String) { + loginSubject.onNext(Pair(id, password)) + } + + fun onViewCleared() { + compositeDisposable.dispose() + } +} \ No newline at end of file diff --git a/Homework/Handnew04/RxStudy/app/src/main/res/layout/activity_example_login.xml b/Homework/Handnew04/RxStudy/app/src/main/res/layout/activity_example_login.xml new file mode 100644 index 0000000..cbbb9d4 --- /dev/null +++ b/Homework/Handnew04/RxStudy/app/src/main/res/layout/activity_example_login.xml @@ -0,0 +1,40 @@ + + + + + + + +