Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/develop' into add/#15-top-app-bar
Browse files Browse the repository at this point in the history
# Conflicts:
#	feature/src/main/res/values/strings.xml
  • Loading branch information
arinming committed Jul 7, 2024
2 parents 4362d0f + 0c48be2 commit 31bf20d
Show file tree
Hide file tree
Showing 23 changed files with 394 additions and 7 deletions.
12 changes: 12 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,14 @@ android {
vectorDrawables {
useSupportLibrary = true
}

buildConfigField(
"String",
"NATIVE_APP_KEY",
gradleLocalProperties(rootDir, providers).getProperty("native.app.key"),
)
manifestPlaceholders["NATIVE_APP_KEY"] =
gradleLocalProperties(rootDir, providers).getProperty("nativeAppKey")
}

buildTypes {
Expand Down Expand Up @@ -104,4 +112,8 @@ dependencies {

debugImplementation(libs.androidx.ui.tooling)
debugImplementation(libs.androidx.ui.test.manifest)

// KakaoDependencies
implementation(libs.kakao.user)

}
6 changes: 6 additions & 0 deletions app/src/main/java/com/terning/point/MyApp.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.terning.point

import android.app.Application
import androidx.appcompat.app.AppCompatDelegate
import com.kakao.sdk.common.KakaoSdk
import dagger.hilt.android.HiltAndroidApp
import timber.log.Timber

Expand All @@ -13,6 +14,7 @@ class MyApp : Application() {

initTimber()
setDayMode()
initKakoSdk()
}

private fun initTimber() {
Expand All @@ -22,4 +24,8 @@ class MyApp : Application() {
private fun setDayMode() {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
}

private fun initKakoSdk() {
KakaoSdk.init(this, BuildConfig.NATIVE_APP_KEY)
}
}
3 changes: 0 additions & 3 deletions core/src/main/java/com/terning/core/extension/ContextExt.kt
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
package com.terning.core.extension

import android.app.Activity
import android.content.Context
import android.view.View
import android.view.inputmethod.InputMethodManager
import android.widget.Toast
import androidx.annotation.StringRes

Expand Down
3 changes: 3 additions & 0 deletions feature/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -91,4 +91,7 @@ dependencies {
implementation(libs.ossLicense)
implementation(libs.lottie)

// KakaoDependencies
implementation(libs.kakao.user)

}
16 changes: 16 additions & 0 deletions feature/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,21 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

<activity
android:name="com.kakao.sdk.auth.AuthCodeHandlerActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.VIEW" />

<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />

<data
android:host="oauth"
android:scheme="kakao${NATIVE_APP_KEY}" />
</intent-filter>
</activity>

</application>
</manifest>
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController
import androidx.navigation.navOptions
import com.terning.feature.calendar.navigation.navigateCalendar
import com.terning.feature.home.navigation.Home
import com.terning.feature.home.navigation.navigateHome
import com.terning.feature.mypage.navigation.navigateMyPage
import com.terning.feature.onboarding.signin.navigation.SignIn
import com.terning.feature.search.navigation.navigateSearch

class MainNavigator(
Expand All @@ -22,7 +22,7 @@ class MainNavigator(
@Composable get() = navController
.currentBackStackEntryAsState().value?.destination

val startDestination = Home
val startDestination = SignIn

val currentTab: MainTab?
@Composable get() = MainTab.find { tab ->
Expand Down
5 changes: 4 additions & 1 deletion feature/src/main/java/com/terning/feature/main/MainScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ import com.terning.core.designsystem.topappbar.MyPageTopAppBar
import com.terning.core.designsystem.topappbar.TerningTopAppBar
import com.terning.feature.home.navigation.homeNavGraph
import com.terning.feature.mypage.navigation.myPageNavGraph
import com.terning.feature.onboarding.signin.navigation.signInNavGraph
import com.terning.feature.onboarding.signup.navigation.signUpNavGraph
import com.terning.feature.search.navigation.searchNavGraph
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.emptyFlow
Expand Down Expand Up @@ -67,6 +69,8 @@ fun MainScreen(
calendarNavGraph()
searchNavGraph()
myPageNavGraph()
signInNavGraph(navHostController = navigator.navController)
signUpNavGraph()
}
}
}
Expand Down Expand Up @@ -117,7 +121,6 @@ private fun MainBottomBar(
}
}


private object NoRippleInteractionSource : MutableInteractionSource {

override val interactions: Flow<Interaction> = emptyFlow()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ fun MyPageRoute(
val context = LocalContext.current
val lifecycleOwner = LocalLifecycleOwner.current

val state by viewModel.state.collectAsStateWithLifecycle(lifecycleOwner = LocalLifecycleOwner.current)
val state by viewModel.state.collectAsStateWithLifecycle(lifecycleOwner = lifecycleOwner)

LaunchedEffect(key1 = true) {
viewModel.getFriendsInfo(2)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.terning.feature.onboarding.filtering

import androidx.compose.runtime.Composable
import com.terning.feature.onboarding.filtering.navigation.FilteringNavigation

@Composable
fun FilteringRoute(){

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package com.terning.feature.onboarding.filtering.navigation

class FilteringNavigation {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package com.terning.feature.onboarding.signin

import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.LocalLifecycleOwner
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.flowWithLifecycle
import androidx.navigation.NavHostController
import com.terning.core.designsystem.theme.TerningTheme
import com.terning.core.extension.toast
import com.terning.feature.R
import com.terning.feature.home.navigation.navigateHome
import com.terning.feature.onboarding.signin.component.KakaoButton

@Composable
fun SignInRoute(
viewModel: SignInViewModel = hiltViewModel(),
navController: NavHostController,
) {
val context = LocalContext.current
val lifecycleOwner = LocalLifecycleOwner.current
val signInState by viewModel.signInState.collectAsStateWithLifecycle(lifecycleOwner = lifecycleOwner)

LaunchedEffect(viewModel.signInSideEffects, lifecycleOwner) {
viewModel.signInSideEffects.flowWithLifecycle(lifecycle = lifecycleOwner.lifecycle)
.collect { sideEffect ->
when (sideEffect) {
is SignInSideEffect.ShowToast -> context.toast(sideEffect.message)
is SignInSideEffect.NavigateToHome -> navController.navigateHome()
}
}
}

SignInScreen(
onSignInClick = { viewModel.startKakaoLogIn(context) }
)
}

@Composable
fun SignInScreen(
modifier: Modifier = Modifier,
onSignInClick: () -> Unit = {}
) {
Column(
modifier = Modifier
.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally
) {
Image(
painter = painterResource(id = R.drawable.img_terning_point),
contentDescription = null,
modifier = Modifier
.size(500.dp),
)
KakaoButton(
title = stringResource(id = R.string.sign_in_kakao_button),
onSignInClick = { onSignInClick() },
modifier = modifier.padding(horizontal = 20.dp)
)
}
}

@Preview(showBackground = true)
@Composable
fun SignInScreenPreview() {
TerningTheme {
SignInScreen()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.terning.feature.onboarding.signin

import androidx.annotation.StringRes

sealed class SignInSideEffect {
data object NavigateToHome : SignInSideEffect()
data class ShowToast(@StringRes val message: Int) : SignInSideEffect()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.terning.feature.onboarding.signin

import com.terning.core.state.UiState

data class SignInState (
val accessToken: UiState<String> = UiState.Loading
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package com.terning.feature.onboarding.signin

import android.content.Context
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.kakao.sdk.auth.model.OAuthToken
import com.kakao.sdk.common.model.ClientError
import com.kakao.sdk.common.model.ClientErrorCause
import com.kakao.sdk.user.UserApiClient
import com.terning.core.state.UiState
import com.terning.feature.R
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
import javax.inject.Inject

@HiltViewModel
class SignInViewModel @Inject constructor() : ViewModel() {

private val _signInState = MutableStateFlow(SignInState())
val signInState: StateFlow<SignInState>
get() = _signInState.asStateFlow()

private val _signInSideEffects = MutableSharedFlow<SignInSideEffect>()
val signInSideEffects: SharedFlow<SignInSideEffect>
get() = _signInSideEffects.asSharedFlow()

fun startKakaoLogIn(context: Context) {
if (UserApiClient.instance.isKakaoTalkLoginAvailable(context)) {
UserApiClient.instance.loginWithKakaoTalk(context) { token, error ->
signInResult(context, token, error)
}
} else {
UserApiClient.instance.loginWithKakaoAccount(context) { token, error ->
signInResult(context, token, error)
}
}
}

private fun signInResult(context: Context, token: OAuthToken?, error: Throwable?) {
viewModelScope.launch {
if (error != null) {
signInFailure(context, error)
} else if (token != null) {
signInSuccess(token)
}
}
}

private fun signInFailure(context: Context, error: Throwable?) {
if (error.toString().contains(KAKAO_NOT_LOGGED_IN)) {
UserApiClient.instance.loginWithKakaoAccount(context) { token, error ->
signInResult(context, token, error)
}
} else {
sigInCancellationOrError(error)
}
}

private fun sigInCancellationOrError(error: Throwable?) {
viewModelScope.launch {
if (error is ClientError && error.reason == ClientErrorCause.Cancelled) {
_signInSideEffects.emit(SignInSideEffect.ShowToast(R.string.sign_in_kakao_cancel))
} else {
_signInSideEffects.emit(SignInSideEffect.ShowToast(R.string.sign_in_kakao_login_fail))
}
}
}

private fun signInSuccess(token: OAuthToken) {
viewModelScope.launch {
_signInState.value =
_signInState.value.copy(accessToken = UiState.Success(token.accessToken))
_signInSideEffects.emit(SignInSideEffect.NavigateToHome)
}
}

companion object {
private const val KAKAO_NOT_LOGGED_IN = "statusCode=302"
}
}
Loading

0 comments on commit 31bf20d

Please sign in to comment.