Skip to content

Commit 3331a09

Browse files
authored
Merge pull request #115 from Stack-Knowledge/feature/34_function_auth
🔀 :: (#34) Google OAuth 구현
2 parents 76282fc + 2585147 commit 3331a09

File tree

80 files changed

+1082
-241
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

80 files changed

+1082
-241
lines changed

app/build.gradle.kts

+3
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ dependencies {
1919
implementation(project(":core:design-system"))
2020
implementation(project(":core:ui"))
2121
implementation(project(":core:model"))
22+
implementation(project(":core:common"))
2223

2324
implementation(project(":feature:login"))
2425
implementation(project(":feature:main"))
@@ -27,5 +28,7 @@ dependencies {
2728
implementation(project(":feature:score-mission"))
2829
implementation(project(":feature:shop"))
2930
implementation(libs.junit)
31+
implementation(libs.google.services)
32+
implementation(libs.play.services.auth)
3033
androidTestImplementation(libs.androidx.test.ext)
3134
}

app/google-services.json

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
"project_info": {
3+
"project_number": "322299804217",
4+
"project_id": "stack-knowledge-v2",
5+
"storage_bucket": "stack-knowledge-v2.appspot.com"
6+
},
7+
"client": [
8+
{
9+
"client_info": {
10+
"mobilesdk_app_id": "1:322299804217:android:e15d7c6ad9b47cc65e2be8",
11+
"android_client_info": {
12+
"package_name": "com.kdn.stack_knowledge"
13+
}
14+
},
15+
"oauth_client": [],
16+
"api_key": [
17+
{
18+
"current_key": "AIzaSyBxMjD7Mg9vzfBiuZVBzyR12Ubr-uEZ_hQ"
19+
}
20+
],
21+
"services": {
22+
"appinvite_service": {
23+
"other_platform_oauth_client": []
24+
}
25+
}
26+
}
27+
],
28+
"configuration_version": "1"
29+
}

app/src/main/AndroidManifest.xml

+5-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<uses-permission android:name="android.permission.INTERNET" />
66

77
<application
8-
android:name="com.stackknowledge.StackKnowledgeApplication"
8+
android:name="com.kdn.stack_knowledge.StackKnowledgeApplication"
99
android:allowBackup="true"
1010
android:dataExtractionRules="@xml/data_extraction_rules"
1111
android:fullBackupContent="@xml/backup_rules"
@@ -15,8 +15,9 @@
1515
android:supportsRtl="true"
1616
android:theme="@style/Theme.StackKnowledge"
1717
tools:targetApi="31">
18+
1819
<activity
19-
android:name="com.stackknowledge.MainActivity"
20+
android:name="com.kdn.stack_knowledge.MainActivity"
2021
android:exported="true"
2122
android:label="@string/app_name"
2223
android:theme="@style/Theme.StackKnowledge">
@@ -26,6 +27,7 @@
2627
<category android:name="android.intent.category.LAUNCHER" />
2728
</intent-filter>
2829
</activity>
30+
2931
</application>
3032

31-
</manifest>
33+
</manifest>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
package com.kdn.stack_knowledge
2+
3+
import android.os.Bundle
4+
import android.util.Log
5+
import android.widget.Toast
6+
import androidx.activity.ComponentActivity
7+
import androidx.activity.OnBackPressedCallback
8+
import androidx.activity.compose.setContent
9+
import androidx.activity.result.contract.ActivityResultContracts
10+
import androidx.activity.viewModels
11+
import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi
12+
import androidx.compose.material3.windowsizeclass.calculateWindowSizeClass
13+
import androidx.compose.runtime.CompositionLocalProvider
14+
import androidx.lifecycle.viewmodel.compose.LocalViewModelStoreOwner
15+
import com.example.common.toast.makeToast
16+
import com.google.android.gms.auth.api.signin.GoogleSignIn
17+
import com.google.android.gms.auth.api.signin.GoogleSignInAccount
18+
import com.google.android.gms.auth.api.signin.GoogleSignInClient
19+
import com.google.android.gms.auth.api.signin.GoogleSignInOptions
20+
import com.google.android.gms.common.api.ApiException
21+
import com.google.android.gms.common.api.Scope
22+
import com.google.android.gms.tasks.Task
23+
import com.stackknowledge.design_system.theme.StackKnowledgeAndroidTheme
24+
import com.stackknowledge.login.viewmodel.AuthViewModel
25+
import com.kdn.stack_knowledge.ui.StackKnowledgeApp
26+
import com.stackknowledge.user.R
27+
import dagger.hilt.android.AndroidEntryPoint
28+
import remote.request.auth.LoginRequestModel
29+
import javax.inject.Inject
30+
import javax.inject.Named
31+
32+
@AndroidEntryPoint
33+
class MainActivity : ComponentActivity() {
34+
35+
@Inject
36+
@Named("GOOGLE_CLIENT_ID")
37+
lateinit var googleClientId: String
38+
39+
@Inject
40+
@Named("SCOPE")
41+
lateinit var scope: String
42+
43+
private val viewModel by viewModels<AuthViewModel>()
44+
45+
private val googleSignInClient: GoogleSignInClient by lazy { getGoogleClient() }
46+
47+
private val googleSignInLauncher =
48+
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
49+
val task: Task<GoogleSignInAccount> =
50+
GoogleSignIn.getSignedInAccountFromIntent(result.data)
51+
handleGoogleSignInResult(task)
52+
}
53+
54+
private var doubleBackToExitPressedOnce = false
55+
56+
private var backPressedTimestamp = 0L
57+
58+
private val onBackPressedCallback = object : OnBackPressedCallback(true) {
59+
override fun handleOnBackPressed() {
60+
controlTheStackWhenBackPressed()
61+
}
62+
}
63+
64+
@OptIn(ExperimentalMaterial3WindowSizeClassApi::class)
65+
override fun onCreate(savedInstanceState: Bundle?) {
66+
super.onCreate(savedInstanceState)
67+
this.onBackPressedDispatcher.addCallback(this, onBackPressedCallback)
68+
setContent {
69+
CompositionLocalProvider(LocalViewModelStoreOwner provides this) {
70+
StackKnowledgeAndroidTheme { _, _ ->
71+
StackKnowledgeApp(
72+
windowSizeClass = calculateWindowSizeClass(this@MainActivity),
73+
onLoginButtonClick = {
74+
googleSocialLogin()
75+
}
76+
)
77+
}
78+
}
79+
}
80+
}
81+
82+
private fun controlTheStackWhenBackPressed() {
83+
val currentTime = System.currentTimeMillis()
84+
if (doubleBackToExitPressedOnce && currentTime - backPressedTimestamp <= 2000) {
85+
finishAffinity()
86+
} else {
87+
doubleBackToExitPressedOnce = true
88+
backPressedTimestamp = currentTime
89+
makeToast(this, getString(R.string.close_app), Toast.LENGTH_SHORT)
90+
}
91+
}
92+
93+
private fun googleSocialLogin() {
94+
googleSignInClient.signOut().addOnCompleteListener {
95+
val signInIntent = googleSignInClient.signInIntent
96+
googleSignInLauncher.launch(signInIntent)
97+
}
98+
}
99+
100+
private fun getGoogleClient(): GoogleSignInClient {
101+
val googleSignInOptions = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
102+
.requestScopes(Scope(scope))
103+
.requestServerAuthCode(googleClientId)
104+
.requestEmail()
105+
.build()
106+
107+
return GoogleSignIn.getClient(this@MainActivity, googleSignInOptions)
108+
}
109+
110+
private fun handleGoogleSignInResult(task: Task<GoogleSignInAccount>) {
111+
val account = task.getResult(ApiException::class.java)
112+
113+
with(viewModel) {
114+
if (isStudent.value) {
115+
loginStudent(body = LoginRequestModel(code = account.serverAuthCode.toString()))
116+
} else {
117+
loginTeacher(body = LoginRequestModel(code = account.serverAuthCode.toString()))
118+
}
119+
}
120+
}
121+
}
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
package com.stackknowledge
1+
package com.kdn.stack_knowledge
22

33
import android.app.Application
44
import dagger.hilt.android.HiltAndroidApp
55

66
@HiltAndroidApp
7-
class StackKnowledgeApplication : Application()
7+
class StackKnowledgeApplication : Application()

app/src/main/java/com/stackknowledge/navigation/StackKnowledgeNavHost.kt app/src/main/java/com/kdn/stack_knowledge/navigation/StackKnowledgeNavHost.kt

+11-10
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package com.stackknowledge.navigation
1+
package com.kdn.stack_knowledge.navigation
22

33
import androidx.compose.runtime.Composable
44
import androidx.compose.ui.Modifier
@@ -8,10 +8,9 @@ import com.stackknowledge.login.navigation.loginScreen
88
import com.stackknowledge.login.navigation.navigateToLogin
99
import com.stackknowledge.login.navigation.roleCheckRoute
1010
import com.stackknowledge.login.navigation.roleCheckScreen
11-
import com.stackknowledge.main.navigation.mainPageRoute
1211
import com.stackknowledge.main.navigation.mainScreen
1312
import com.stackknowledge.main.navigation.navigateToMain
14-
import com.stackknowledge.navigation.util.bottomNavigationNavigate
13+
import com.kdn.stack_knowledge.navigation.util.bottomNavigationNavigate
1514
import com.stackknowledge.ranking.navigation.navigateToRanking
1615
import com.stackknowledge.ranking.navigation.navigateToTeacherRanking
1716
import com.stackknowledge.ranking.navigation.rankingScreen
@@ -24,21 +23,20 @@ import com.stackknowledge.shop.navigation.shopRoute
2423
import com.stackknowledge.shop.navigation.shopScreen
2524
import com.stackknowledge.shop.navigation.teacherShopRoute
2625
import com.stackknowledge.shop.navigation.teacherShopScreen
27-
import com.stackknowledge.ui.StackKnowledgeAppState
28-
import com.stackkowledge.mission.navigation.createMissionRoute
26+
import com.kdn.stack_knowledge.ui.StackKnowledgeAppState
2927
import com.stackkowledge.mission.navigation.createMissionScreen
30-
import com.stackkowledge.mission.navigation.entireMissionRoute
3128
import com.stackkowledge.mission.navigation.entireMissionScreen
3229
import com.stackkowledge.mission.navigation.navigateToEntireMission
3330
import com.stackkowledge.mission.navigation.navigateToResolveMission
3431
import com.stackkowledge.mission.navigation.resolveMissionScreen
35-
import enumdatatype.Authority
32+
import enumdata.Authority
3633

3734
@Composable
3835
fun StackKnowledgeNavHost(
3936
appState: StackKnowledgeAppState,
40-
modifier: Modifier = Modifier,
4137
startDestination: String = roleCheckRoute,
38+
modifier: Modifier = Modifier,
39+
onLoginButtonClick: () -> Unit = {},
4240
) {
4341
val navController = appState.navController
4442

@@ -47,9 +45,12 @@ fun StackKnowledgeNavHost(
4745
startDestination = startDestination,
4846
modifier = modifier
4947
) {
50-
loginScreen()
48+
loginScreen(
49+
onSuccess = navController::navigateToMain,
50+
onLoginButtonClick = onLoginButtonClick
51+
)
5152
roleCheckScreen(
52-
onRoleClick = navController::navigateToLogin
53+
onRoleButtonClick = navController::navigateToLogin
5354
)
5455
mainScreen(
5556
onNavigate = { role, navType, index ->
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package com.kdn.stack_knowledge.navigation
2+
3+
enum class TopLevelDestination {
4+
ROLE_CHECK,
5+
}

app/src/main/java/com/stackknowledge/navigation/util/BottomNavigationNavigate.kt app/src/main/java/com/kdn/stack_knowledge/navigation/util/BottomNavigationNavigate.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package com.stackknowledge.navigation.util
1+
package com.kdn.stack_knowledge.navigation.util
22

33
import androidx.navigation.NavController
44
import androidx.navigation.NavGraph.Companion.findStartDestination
@@ -12,7 +12,7 @@ import com.stackknowledge.shop.navigation.navigateToShop
1212
import com.stackknowledge.shop.navigation.navigateToTeacherShop
1313
import com.stackkowledge.mission.navigation.navigateToCreateMission
1414
import com.stackkowledge.mission.navigation.navigateToEntireMission
15-
import enumdatatype.Authority
15+
import enumdata.Authority
1616

1717
fun bottomNavigationNavigate(
1818
role: Authority,
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,22 @@
1-
package com.stackknowledge.ui
1+
package com.kdn.stack_knowledge.ui
22

33
import androidx.compose.material3.windowsizeclass.WindowSizeClass
44
import androidx.compose.runtime.Composable
55
import com.stackknowledge.design_system.theme.StackKnowledgeAndroidTheme
6-
import com.stackknowledge.navigation.StackKnowledgeNavHost
6+
import com.kdn.stack_knowledge.navigation.StackKnowledgeNavHost
77

88
@Composable
99
fun StackKnowledgeApp(
1010
windowSizeClass: WindowSizeClass,
1111
appState: StackKnowledgeAppState = rememberStackKnowledgeAppState(
1212
windowSizeClass = windowSizeClass
1313
),
14+
onLoginButtonClick: () -> Unit = {},
1415
) {
1516
StackKnowledgeAndroidTheme { _, _ ->
16-
StackKnowledgeNavHost(
17-
appState = appState,
18-
//startDestination = "" <- auth 작업후에 추가
19-
)
17+
StackKnowledgeNavHost(
18+
appState = appState,
19+
onLoginButtonClick = onLoginButtonClick
20+
)
2021
}
2122
}

app/src/main/java/com/stackknowledge/ui/StackKnowledgeAppState.kt app/src/main/java/com/kdn/stack_knowledge/ui/StackKnowledgeAppState.kt

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
1-
package com.stackknowledge.ui
1+
package com.kdn.stack_knowledge.ui
22

33
import androidx.compose.material3.windowsizeclass.WindowSizeClass
44
import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass
55
import androidx.compose.runtime.Composable
66
import androidx.compose.runtime.Stable
77
import androidx.compose.runtime.remember
88
import androidx.compose.runtime.rememberCoroutineScope
9-
import androidx.navigation.NavController
109
import androidx.navigation.NavDestination
1110
import androidx.navigation.NavHostController
1211
import androidx.navigation.compose.currentBackStackEntryAsState
1312
import androidx.navigation.compose.rememberNavController
14-
import com.stackknowledge.navigation.TopLevelDestination
13+
import com.kdn.stack_knowledge.navigation.TopLevelDestination
14+
import com.stackknowledge.login.navigation.roleCheckRoute
1515
import kotlinx.coroutines.CoroutineScope
1616

1717
@Composable
@@ -45,7 +45,7 @@ class StackKnowledgeAppState(
4545

4646
val currentTopLevelDestination: TopLevelDestination?
4747
@Composable get() = when(currentDestination?.route) {
48-
// loginRoute 작성
48+
roleCheckRoute -> TopLevelDestination.ROLE_CHECK
4949
else -> null
5050
}
5151

0 commit comments

Comments
 (0)