Skip to content

Commit a1618ee

Browse files
authored
feat: 심사 완료 페이지 구현 (#61)
* feat: 승인/매칭 대기화면 ui 파일 구조 추가 * feat: ui 튜닝 (logoOffest으로 로고 위치 조정, CustomText로 변경) * feat: DataStore 기반 Router 분기 및 승인대기/매칭대기 화면 연결
1 parent 77bd929 commit a1618ee

File tree

14 files changed

+314
-46
lines changed

14 files changed

+314
-46
lines changed

app/src/main/java/com/apptive/japkor/MainActivity.kt

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,6 @@ class MainActivity : ComponentActivity() {
7373
setContent {
7474
JapKorTheme {
7575
MainScreen(
76-
startDestination = startDestination,
7776
onRequestNotificationPermission = ::requestNotificationPermission
7877
)
7978
}
@@ -98,15 +97,17 @@ class MainActivity : ComponentActivity() {
9897

9998
@Composable
10099
fun MainScreen(
101-
startDestination: String,
102100
onRequestNotificationPermission: () -> Unit
103101
) {
104-
var signedIn by remember { mutableStateOf(false) }
105102
val navController = rememberNavController()
106103
val toastManager = remember { ToastManager() }
107104
val context = LocalContext.current
108105
val dataStore = remember { DataStoreManager(context) }
109-
val languageCode by dataStore.getLanguage().collectAsState(initial = AppLanguage.Korean.code)
106+
107+
val languageCode by dataStore
108+
.getLanguage()
109+
.collectAsState(initial = AppLanguage.Korean.code)
110+
110111
val appLanguage = AppLanguage.fromCode(languageCode)
111112

112113
LaunchedEffect(Unit) {
@@ -117,12 +118,11 @@ fun MainScreen(
117118
CompositionLocalProvider(LocalAppLanguage provides appLanguage) {
118119
Box(modifier = Modifier.fillMaxSize()) {
119120
AppNavHost(
120-
navController = navController,
121-
isSignedIn = signedIn,
122-
startDestination = startDestination
121+
navController = navController
123122
)
124123
CustomToastContainer(manager = toastManager)
125124
}
126125
}
127126
}
128127
}
128+

app/src/main/java/com/apptive/japkor/data/local/DataStoreManager.kt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,20 @@ class DataStoreManager(private val context: Context) {
4343
)
4444
}
4545

46+
fun getUserName() = context.dataStore.data.map { it[KEY_NAME] ?: "" }
47+
48+
suspend fun saveUserName(name: String) {
49+
context.dataStore.edit { prefs ->
50+
prefs[KEY_NAME] = name
51+
}
52+
}
53+
54+
suspend fun saveUserStatus(status: String) {
55+
context.dataStore.edit { prefs ->
56+
prefs[KEY_STATUS] = status
57+
}
58+
}
59+
4660
suspend fun saveFcmToken(token: String) {
4761
context.dataStore.edit { prefs ->
4862
prefs[KEY_FCM_TOKEN] = token

app/src/main/java/com/apptive/japkor/navigation/AppNavHost.kt

Lines changed: 27 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -9,46 +9,49 @@ import com.apptive.japkor.ui.login.LoginScreen
99
import com.apptive.japkor.ui.requiredinfo.RequiredInfoCompleteScreen
1010
import com.apptive.japkor.ui.requiredinfo.RequiredInfoScreen
1111
import com.apptive.japkor.ui.signup.SignUpScreen
12+
import com.apptive.japkor.ui.status.PendingApprovalRouteScreen
13+
import com.apptive.japkor.ui.status.PendingConnectingRouteScreen
1214

1315
sealed class Screen(val route: String) {
14-
object Login : Screen("login")
16+
object Router : Screen("router")
1517

18+
object Login : Screen("login")
1619
object Language : Screen("language")
20+
object SignUp : Screen("signup")
1721

1822
object RequiredInfo : Screen("requiredinfo")
19-
2023
object RequiredInfoComplete : Screen("requiredinfo_complete")
2124

22-
object SignUp : Screen("signup")
25+
// placeholder 기능
26+
object PendingApproval : Screen("pending_approval")
27+
object PendingConnecting : Screen("pending_connecting")
28+
object Connected : Screen("connected")
29+
object Blacklisted : Screen("blacklisted")
2330
}
2431

2532
@Composable
2633
fun AppNavHost(
27-
navController: NavHostController,
28-
isSignedIn: Boolean,
29-
startDestination: String = Screen.Language.route // 이거 왜 생겼냐면 로그인 콜백에서 바로 이동하려고
34+
navController: NavHostController
3035
) {
3136
NavHost(
3237
navController = navController,
33-
startDestination = startDestination
38+
startDestination = Screen.Router.route
3439
) {
35-
composable(Screen.Language.route) {
36-
LanguageScreen(navController)
37-
}
38-
composable(Screen.Login.route) {
39-
LoginScreen(navController)
40+
composable(Screen.Router.route) {
41+
RouterScreen(navController)
4042
}
41-
composable(Screen.RequiredInfo.route) {
42-
RequiredInfoScreen(navController)
43-
}
44-
composable(Screen.RequiredInfoComplete.route) {
45-
RequiredInfoCompleteScreen(navController)
46-
}
47-
composable(
48-
route = Screen.SignUp.route,
49-
content = {
50-
SignUpScreen(navController)
51-
}
52-
)
43+
44+
composable(Screen.Language.route) { LanguageScreen(navController) }
45+
composable(Screen.Login.route) { LoginScreen(navController) }
46+
composable(Screen.SignUp.route) { SignUpScreen(navController) }
47+
48+
composable(Screen.RequiredInfo.route) { RequiredInfoScreen(navController) }
49+
composable(Screen.RequiredInfoComplete.route) { RequiredInfoCompleteScreen(navController) }
50+
51+
composable(Screen.PendingApproval.route) { PendingApprovalRouteScreen() }
52+
composable(Screen.PendingConnecting.route) { PendingConnectingRouteScreen() }
53+
54+
//composable(Screen.Connected.route) { ConnectedPlaceholderScreen(navController) }
55+
//composable(Screen.Blacklisted.route) { BlacklistedPlaceholderScreen(navController) }
5356
}
5457
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package com.apptive.japkor.navigation
2+
3+
import androidx.compose.runtime.Composable
4+
import androidx.compose.runtime.LaunchedEffect
5+
import androidx.compose.runtime.remember
6+
import androidx.compose.ui.platform.LocalContext
7+
import androidx.navigation.NavHostController
8+
import com.apptive.japkor.data.local.DataStoreManager
9+
import com.apptive.japkor.data.local.TokenProvider
10+
import com.apptive.japkor.data.model.UserStatus
11+
import kotlinx.coroutines.flow.first
12+
13+
@Composable
14+
fun RouterScreen(
15+
navController: NavHostController
16+
) {
17+
val context = LocalContext.current
18+
val dataStore = remember {
19+
DataStoreManager(context.applicationContext)
20+
}
21+
22+
LaunchedEffect(Unit) {
23+
val token = dataStore.getUserToken().first()
24+
25+
// 1️⃣ 토큰 없으면 → Language
26+
if (token.isBlank()) {
27+
navController.navigate(Screen.Language.route) {
28+
popUpTo(Screen.Router.route) { inclusive = true }
29+
}
30+
return@LaunchedEffect
31+
}
32+
33+
// 2️⃣ 토큰 있으면 메모리에 세팅
34+
TokenProvider.setToken(token)
35+
36+
// 3️⃣ status 읽기
37+
val statusStr = dataStore.getUserStatus().first()
38+
val status = runCatching {
39+
UserStatus.valueOf(statusStr)
40+
}.getOrNull()
41+
42+
// 4️⃣ status → 목적지 결정
43+
val targetRoute = when (status) {
44+
UserStatus.INCOMPLETE_PROFILE -> Screen.RequiredInfo.route
45+
UserStatus.PENDING_APPROVAL -> Screen.PendingApproval.route
46+
UserStatus.APPROVED -> Screen.PendingConnecting.route
47+
UserStatus.CONNECTING,
48+
UserStatus.CONNECTED -> Screen.Connected.route
49+
UserStatus.BLACKLISTED -> Screen.Blacklisted.route
50+
null -> Screen.Login.route
51+
}
52+
53+
// 5️⃣ Router 제거 + 이동
54+
navController.navigate(targetRoute) {
55+
popUpTo(Screen.Router.route) { inclusive = true }
56+
launchSingleTop = true
57+
}
58+
}
59+
60+
// 👀 사용자에게 보이는 UI (간단한 로딩/스플래시)
61+
//SplashLoadingScreen()
62+
}

app/src/main/java/com/apptive/japkor/ui/login/LoginScreen.kt

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -210,18 +210,10 @@ fun LoginScreen(navController: NavController,viewModel: LoginScreenViewModel = v
210210
viewModel.signIn(email, password) { success, status ->
211211
if (success) {
212212
toastManager.success("로그인 성공! 환영합니다.")
213-
when (status) {
214-
UserStatus.INCOMPLETE_PROFILE -> {
215-
navController.navigate(Screen.RequiredInfo.route)
216-
}
217-
UserStatus.PENDING_APPROVAL,
218-
UserStatus.APPROVED,
219-
UserStatus.CONNECTING,
220-
UserStatus.CONNECTED,
221-
UserStatus.BLACKLISTED -> {
222-
navController.navigate(Screen.RequiredInfoComplete.route)
223-
}
224-
null -> navController.navigate(Screen.RequiredInfo.route)
213+
214+
navController.navigate(Screen.Router.route) {
215+
popUpTo(Screen.Login.route) { inclusive = true }
216+
launchSingleTop = true
225217
}
226218
} else {
227219
toastManager.error("로그인 실패! 이메일과 비밀번호를 확인해주세요.")

app/src/main/java/com/apptive/japkor/ui/requiredinfo/RequiredInfoCompleteScreen.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,9 @@ fun RequiredInfoCompleteScreen(navController: NavController) {
133133

134134
Button(
135135
onClick = {
136-
navController.navigate(Screen.Language.route) {
137-
popUpTo(Screen.Language.route) { inclusive = false }
136+
navController.navigate(Screen.PendingApproval.route) {
137+
popUpTo(Screen.RequiredInfoComplete.route) { inclusive = true }
138+
launchSingleTop = true
138139
}
139140
},
140141
modifier = Modifier.fillMaxWidth(),

app/src/main/java/com/apptive/japkor/ui/requiredinfo/RequiredInfoScreen.kt

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,16 @@ import androidx.compose.runtime.remember
3232
import androidx.compose.ui.Alignment
3333
import androidx.compose.ui.Modifier
3434
import androidx.compose.ui.graphics.Color
35+
import androidx.compose.ui.platform.LocalContext
3536
import androidx.compose.ui.platform.LocalLayoutDirection
3637
import androidx.compose.ui.res.painterResource
3738
import androidx.compose.ui.unit.dp
39+
import androidx.lifecycle.ViewModel
40+
import androidx.lifecycle.ViewModelProvider
3841
import androidx.lifecycle.viewmodel.compose.viewModel
3942
import androidx.navigation.NavController
4043
import com.apptive.japkor.R
44+
import com.apptive.japkor.data.local.DataStoreManager
4145
import com.apptive.japkor.navigation.Screen
4246
import com.apptive.japkor.ui.components.CustomText
4347
import com.apptive.japkor.ui.components.CustomTextType
@@ -61,7 +65,17 @@ fun RequiredInfoScreen(
6165
onSubmit: (name: String, email: String) -> Unit = { _, _ -> },
6266
initialStep: Int = 1
6367
) {
64-
val requiredInfoViewModel: RequiredInfoViewModel = viewModel()
68+
val context = LocalContext.current
69+
70+
val requiredInfoViewModel: RequiredInfoViewModel = viewModel(
71+
factory = object : ViewModelProvider.Factory {
72+
override fun <T : ViewModel> create(modelClass: Class<T>): T {
73+
return RequiredInfoViewModel(
74+
dataStore = DataStoreManager(context.applicationContext)
75+
) as T
76+
}
77+
}
78+
)
6579
val toastManager = LocalToastManager.current
6680
val appLanguage = LocalAppLanguage.current
6781

app/src/main/java/com/apptive/japkor/ui/requiredinfo/RequiredInfoViewModel.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@ import android.provider.OpenableColumns
66
import android.util.Log
77
import androidx.lifecycle.ViewModel
88
import androidx.lifecycle.viewModelScope
9+
import com.apptive.japkor.data.local.DataStoreManager
910
import com.apptive.japkor.data.model.PresignedUrlRequest
1011
import com.apptive.japkor.data.model.RequiredInfoDTO
12+
import com.apptive.japkor.data.model.UserStatus
1113
import com.apptive.japkor.data.repository.ApiResult
1214
import com.apptive.japkor.data.repository.RequiredInfoRepository
1315
import com.apptive.japkor.ui.components.ToastType
@@ -46,6 +48,7 @@ sealed class RequiredInfoEvent {
4648
}
4749

4850
class RequiredInfoViewModel(
51+
private val dataStore: DataStoreManager,
4952
private val repository: RequiredInfoRepository = RequiredInfoRepository()
5053
) : ViewModel() {
5154

@@ -418,6 +421,8 @@ class RequiredInfoViewModel(
418421

419422
if (result.success && result.code in 200..299) {
420423
_submitState.value = SubmitState.Success
424+
dataStore.saveUserName(name)
425+
dataStore.saveUserStatus(UserStatus.PENDING_APPROVAL.name)
421426
_events.emit(RequiredInfoEvent.NavigateToComplete)
422427
} else {
423428
val message = result.errorMessage ?: "알 수 없는 오류가 발생했습니다."
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package com.apptive.japkor.ui.status
2+
3+
import androidx.compose.runtime.Composable
4+
import androidx.compose.runtime.collectAsState
5+
import androidx.compose.runtime.getValue
6+
import androidx.compose.runtime.remember
7+
import androidx.compose.ui.platform.LocalContext
8+
import com.apptive.japkor.R
9+
import com.apptive.japkor.data.local.DataStoreManager
10+
11+
@Composable
12+
fun PendingApprovalRouteScreen() {
13+
val context = LocalContext.current
14+
val dataStore = remember { DataStoreManager(context.applicationContext) }
15+
16+
val name by dataStore.getUserName().collectAsState(initial = "")
17+
18+
PendingApprovalScreen(
19+
name = name.ifBlank { "회원" },
20+
logoRes = R.drawable.ampersand_bg
21+
)
22+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.apptive.japkor.ui.status
2+
3+
import androidx.annotation.DrawableRes
4+
import androidx.compose.runtime.Composable
5+
import androidx.compose.ui.unit.dp
6+
7+
@Composable
8+
fun PendingApprovalScreen(
9+
name: String,
10+
@DrawableRes logoRes: Int
11+
) {
12+
StatusWaitingTemplate(
13+
name = name,
14+
title = "프로필을 심사 중이에요!",
15+
subtitle = "조금만 더 기다려주세요",
16+
logoRes = logoRes,
17+
logoOffsetX = (-150).dp // 왼쪽으로 밀기 (여기 값만 튜닝)
18+
)
19+
}

0 commit comments

Comments
 (0)