diff --git a/app/src/main/java/com/peonlee/PeonleeApplication.kt b/app/src/main/java/com/peonlee/PeonleeApplication.kt index 129674a4..802b0437 100644 --- a/app/src/main/java/com/peonlee/PeonleeApplication.kt +++ b/app/src/main/java/com/peonlee/PeonleeApplication.kt @@ -17,6 +17,7 @@ package com.peonlee import android.app.Application +import androidx.appcompat.app.AppCompatDelegate import com.kakao.sdk.common.KakaoSdk import dagger.hilt.android.HiltAndroidApp @@ -24,7 +25,7 @@ import dagger.hilt.android.HiltAndroidApp class PeonleeApplication : Application() { override fun onCreate() { super.onCreate() - KakaoSdk.init(this, BuildConfig.KAKAO_NATIVE_KEY) + AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO) } } diff --git a/core/ui/src/main/res/drawable/bg_brand30_outline_brand60_radius_10dp.xml b/core/ui/src/main/res/drawable/bg_brand30_outline_brand60_radius_10dp.xml new file mode 100644 index 00000000..a9b02958 --- /dev/null +++ b/core/ui/src/main/res/drawable/bg_brand30_outline_brand60_radius_10dp.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/feature/login/build.gradle.kts b/feature/login/build.gradle.kts index 9b631209..dc39c52f 100644 --- a/feature/login/build.gradle.kts +++ b/feature/login/build.gradle.kts @@ -18,6 +18,7 @@ dependencies { implementation(project(":core:data")) implementation(project(":feature:main")) + implementation(project(":feature:terms")) implementation(platform(libs.firebase.bom)) implementation(libs.firebase.analytics) diff --git a/feature/login/src/main/java/com/peonlee/login/LoginActivity.kt b/feature/login/src/main/java/com/peonlee/login/LoginActivity.kt index f678b60f..09211837 100644 --- a/feature/login/src/main/java/com/peonlee/login/LoginActivity.kt +++ b/feature/login/src/main/java/com/peonlee/login/LoginActivity.kt @@ -17,6 +17,7 @@ import com.kakao.sdk.common.model.ClientErrorCause import com.kakao.sdk.user.UserApiClient import com.peonlee.core.ui.base.BaseActivity import com.peonlee.core.ui.extensions.showToast +import com.peonlee.feature.terms.TermsActivity import com.peonlee.login.databinding.ActivityLoginBinding import com.peonlee.main.MainActivity import dagger.hilt.android.AndroidEntryPoint @@ -29,6 +30,11 @@ class LoginActivity : BaseActivity() { googleSignInResult(activityResult) } + private val agreeTermsLauncher: ActivityResultLauncher = + registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { activityResult -> + termsResult(activityResult) + } + private val loginViewModel: LoginViewModel by viewModels() override fun bindingFactory() = ActivityLoginBinding.inflate(layoutInflater) @@ -48,9 +54,11 @@ class LoginActivity : BaseActivity() { is LoginState.Success -> { loginViewModel.setToken(loginState.data.accessToken) startActivity(Intent(this@LoginActivity, MainActivity::class.java)) + finish() } - is LoginState.Already -> { - // TODO : 약관 화면 이동 + is LoginState.NotRegistered -> { + val intent = Intent(this@LoginActivity, TermsActivity::class.java) + agreeTermsLauncher.launch(intent) } is LoginState.Fail -> showToast(R.string.server_error) } @@ -99,7 +107,11 @@ class LoginActivity : BaseActivity() { } loginWithKakaoAccount() } - token != null -> loginViewModel.login(token.accessToken, "KAKAO") + token != null -> { + token.idToken?.let { idToken -> + loginViewModel.login(idToken, "KAKAO") + } ?: showToast(R.string.invalid_token) + } } } } else { @@ -116,4 +128,11 @@ class LoginActivity : BaseActivity() { } return UserApiClient.instance.loginWithKakaoAccount(this, callback = kakaoLoginCallback) } + + private fun termsResult(activityResult: ActivityResult) { + when (activityResult.resultCode) { + Activity.RESULT_OK -> loginViewModel.signUp() + else -> Unit + } + } } diff --git a/feature/login/src/main/java/com/peonlee/login/LoginViewModel.kt b/feature/login/src/main/java/com/peonlee/login/LoginViewModel.kt index 15ce3039..5c259701 100644 --- a/feature/login/src/main/java/com/peonlee/login/LoginViewModel.kt +++ b/feature/login/src/main/java/com/peonlee/login/LoginViewModel.kt @@ -21,19 +21,28 @@ class LoginViewModel @Inject constructor( private val dataStore: LocalDataSource ) : ViewModel() { + var loginType: String = "" + private set + + var loginToken: String = "" + private set + private val _loginState: MutableSharedFlow = MutableStateFlow(LoginState.Init) val loginState = _loginState.asSharedFlow() fun login(token: String, type: String) { + loginType = type + loginToken = token + viewModelScope.launch { val loginResult = loginUseCase.login(token, setRequest(token, type)) handleState(loginResult) } } - fun signUp(token: String, type: String) { + fun signUp() { viewModelScope.launch { - val signUpResult = loginUseCase.signUp(token, setRequest(token, type)) + val signUpResult = loginUseCase.signUp(loginToken, setRequest(loginToken, loginType)) handleState(signUpResult) } } @@ -53,7 +62,7 @@ class LoginViewModel @Inject constructor( is Result.Error -> { when (result.exception.message?.contains("status") ?: false) { // TODO : 리팩토링 data layer에서 파싱 true -> _loginState.emit(LoginState.Fail) - false -> _loginState.emit(LoginState.Already) + false -> _loginState.emit(LoginState.NotRegistered) } } } @@ -66,6 +75,6 @@ class LoginViewModel @Inject constructor( sealed class LoginState { object Init : LoginState() data class Success(val data: AuthResult) : LoginState() - object Already : LoginState() + object NotRegistered : LoginState() object Fail : LoginState() } diff --git a/feature/login/src/main/res/values/string.xml b/feature/login/src/main/res/values/string.xml index c9d2f770..50486bdd 100644 --- a/feature/login/src/main/res/values/string.xml +++ b/feature/login/src/main/res/values/string.xml @@ -5,4 +5,5 @@ 카카오로 로그인 구글로 로그인 서버에러 고객센터에 문의해주세요. + 토큰이 유효하지 않습니다. \ No newline at end of file diff --git a/feature/terms/build.gradle.kts b/feature/terms/build.gradle.kts new file mode 100644 index 00000000..2597bd48 --- /dev/null +++ b/feature/terms/build.gradle.kts @@ -0,0 +1,17 @@ +plugins { + id("peonlee.android.feature") +} + +android { + namespace = "com.peonlee.terms" + viewBinding { enable = true } +} + +dependencies { + implementation(project(":core:ui")) + implementation(project(":core:common")) + implementation(project(":core:data")) + + implementation(libs.androidx.constraintlayout) + implementation(libs.kotlinx.coroutines.android) +} diff --git a/feature/terms/src/androidTest/java/com/peonlee/feature/terms/ExampleInstrumentedTest.kt b/feature/terms/src/androidTest/java/com/peonlee/feature/terms/ExampleInstrumentedTest.kt new file mode 100644 index 00000000..ad92ff8a --- /dev/null +++ b/feature/terms/src/androidTest/java/com/peonlee/feature/terms/ExampleInstrumentedTest.kt @@ -0,0 +1,22 @@ +package com.peonlee.feature.terms + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.platform.app.InstrumentationRegistry +import org.junit.Assert.assertEquals +import org.junit.Test +import org.junit.runner.RunWith + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("com.peonlee.feature.terms", appContext.packageName) + } +} diff --git a/feature/terms/src/main/AndroidManifest.xml b/feature/terms/src/main/AndroidManifest.xml new file mode 100644 index 00000000..4a1c390e --- /dev/null +++ b/feature/terms/src/main/AndroidManifest.xml @@ -0,0 +1,9 @@ + + + + + + + \ No newline at end of file diff --git a/feature/terms/src/main/java/com/peonlee/feature/terms/TermsActivity.kt b/feature/terms/src/main/java/com/peonlee/feature/terms/TermsActivity.kt new file mode 100644 index 00000000..c5f4031b --- /dev/null +++ b/feature/terms/src/main/java/com/peonlee/feature/terms/TermsActivity.kt @@ -0,0 +1,73 @@ +package com.peonlee.feature.terms + +import android.app.Activity +import android.content.res.ColorStateList +import androidx.core.content.ContextCompat +import com.peonlee.core.ui.base.BaseActivity +import com.peonlee.terms.databinding.ActivityTermsBinding +import com.peonlee.core.ui.R.color as Color +import com.peonlee.core.ui.R.drawable as Drawable + +class TermsActivity : BaseActivity() { + override fun bindingFactory(): ActivityTermsBinding = ActivityTermsBinding.inflate(layoutInflater) + + override fun initViews() = with(binding) { + ivTermsClose.setOnClickListener { + setResult(Activity.RESULT_OK) + finish() + } + + checkboxAllTerms.apply { + setOnClickListener { + checkboxService.isChecked = isChecked + checkboxPersonal.isChecked = isChecked + updateBackground(isChecked) + updateNextButton() + } + } + + checkboxService.setOnClickListener { + checkboxAllTerms.isChecked = false + updateBackground(false) + updateNextButton() + } + + checkboxPersonal.setOnClickListener { + checkboxAllTerms.isChecked = false + updateBackground(false) + updateNextButton() + } + + tvStart.setOnClickListener { + setResult(Activity.RESULT_OK) + finish() + } + } + + private fun updateBackground(isUpdate: Boolean) { + when (isUpdate) { + true -> binding.layoutTerms.setBackgroundResource(Drawable.bg_brand30_outline_brand60_radius_10dp) + false -> binding.layoutTerms.setBackgroundResource(Drawable.bg_white_outline_radius_10dp) + } + } + + private fun updateNextButton() { + val isActive = binding.checkboxService.isChecked && binding.checkboxPersonal.isChecked + when (isActive) { + true -> updateState(true) + false -> updateState(false) + } + } + + private fun updateState(isActive: Boolean) { + binding.tvStart.apply { + isEnabled = isActive + backgroundTintList = ColorStateList.valueOf( + ContextCompat.getColor( + this@TermsActivity, + if (isActive) Color.brand100 else Color.brand50 + ) + ) + } + } +} diff --git a/feature/terms/src/main/res/layout/activity_terms.xml b/feature/terms/src/main/res/layout/activity_terms.xml new file mode 100644 index 00000000..458d6ae2 --- /dev/null +++ b/feature/terms/src/main/res/layout/activity_terms.xml @@ -0,0 +1,137 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/feature/terms/src/main/res/values/dimens.xml b/feature/terms/src/main/res/values/dimens.xml new file mode 100644 index 00000000..e746dd34 --- /dev/null +++ b/feature/terms/src/main/res/values/dimens.xml @@ -0,0 +1,9 @@ + +> + 30dp + 50dp + 44dp + 26dp + 56dp + 24dp + \ No newline at end of file diff --git a/feature/terms/src/main/res/values/strings.xml b/feature/terms/src/main/res/values/strings.xml new file mode 100644 index 00000000..e95106ca --- /dev/null +++ b/feature/terms/src/main/res/values/strings.xml @@ -0,0 +1,9 @@ + + 편리에 오신 것을 환영해요 + 편리 서비스 이용을 위해 + 필수 약관에 동의해 주세요 + 약관 전체동의 + 서비스 이용약관 동의 + 개인정보 수집 및 이용동의 + 시작하기 + \ No newline at end of file diff --git a/feature/terms/src/test/java/com/peonlee/feature/terms/ExampleUnitTest.kt b/feature/terms/src/test/java/com/peonlee/feature/terms/ExampleUnitTest.kt new file mode 100644 index 00000000..fed869fd --- /dev/null +++ b/feature/terms/src/test/java/com/peonlee/feature/terms/ExampleUnitTest.kt @@ -0,0 +1,16 @@ +package com.peonlee.feature.terms + +import org.junit.Assert.assertEquals +import org.junit.Test + +/** + * Example local unit test, which will execute on the development machine (host). + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +class ExampleUnitTest { + @Test + fun addition_isCorrect() { + assertEquals(4, 2 + 2) + } +} diff --git a/settings.gradle.kts b/settings.gradle.kts index 6455d2aa..f42748f1 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -51,3 +51,4 @@ include(":core:common") include(":feature:user") include(":feature:product") include(":feature:onboard") +include(":feature:terms")