Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions app/src/main/java/com/apptive/japkor/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@ class MainActivity : ComponentActivity() {
setContent {
JapKorTheme {
MainScreen(
startDestination = startDestination,
onRequestNotificationPermission = ::requestNotificationPermission
)
}
Expand All @@ -98,15 +97,17 @@ class MainActivity : ComponentActivity() {

@Composable
fun MainScreen(
startDestination: String,
onRequestNotificationPermission: () -> Unit
) {
var signedIn by remember { mutableStateOf(false) }
val navController = rememberNavController()
val toastManager = remember { ToastManager() }
val context = LocalContext.current
val dataStore = remember { DataStoreManager(context) }
val languageCode by dataStore.getLanguage().collectAsState(initial = AppLanguage.Korean.code)

val languageCode by dataStore
.getLanguage()
.collectAsState(initial = AppLanguage.Korean.code)

val appLanguage = AppLanguage.fromCode(languageCode)

LaunchedEffect(Unit) {
Expand All @@ -117,12 +118,11 @@ fun MainScreen(
CompositionLocalProvider(LocalAppLanguage provides appLanguage) {
Box(modifier = Modifier.fillMaxSize()) {
AppNavHost(
navController = navController,
isSignedIn = signedIn,
startDestination = startDestination
navController = navController
)
CustomToastContainer(manager = toastManager)
}
}
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,20 @@ class DataStoreManager(private val context: Context) {
)
}

fun getUserName() = context.dataStore.data.map { it[KEY_NAME] ?: "" }

suspend fun saveUserName(name: String) {
context.dataStore.edit { prefs ->
prefs[KEY_NAME] = name
}
}

suspend fun saveUserStatus(status: String) {
context.dataStore.edit { prefs ->
prefs[KEY_STATUS] = status
}
}

suspend fun saveFcmToken(token: String) {
context.dataStore.edit { prefs ->
prefs[KEY_FCM_TOKEN] = token
Expand Down
51 changes: 27 additions & 24 deletions app/src/main/java/com/apptive/japkor/navigation/AppNavHost.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,46 +9,49 @@ import com.apptive.japkor.ui.login.LoginScreen
import com.apptive.japkor.ui.requiredinfo.RequiredInfoCompleteScreen
import com.apptive.japkor.ui.requiredinfo.RequiredInfoScreen
import com.apptive.japkor.ui.signup.SignUpScreen
import com.apptive.japkor.ui.status.PendingApprovalRouteScreen
import com.apptive.japkor.ui.status.PendingConnectingRouteScreen

sealed class Screen(val route: String) {
object Login : Screen("login")
object Router : Screen("router")

object Login : Screen("login")
object Language : Screen("language")
object SignUp : Screen("signup")

object RequiredInfo : Screen("requiredinfo")

object RequiredInfoComplete : Screen("requiredinfo_complete")

object SignUp : Screen("signup")
// placeholder 기능
object PendingApproval : Screen("pending_approval")
object PendingConnecting : Screen("pending_connecting")
object Connected : Screen("connected")
object Blacklisted : Screen("blacklisted")
}

@Composable
fun AppNavHost(
navController: NavHostController,
isSignedIn: Boolean,
startDestination: String = Screen.Language.route // 이거 왜 생겼냐면 로그인 콜백에서 바로 이동하려고
navController: NavHostController
) {
NavHost(
navController = navController,
startDestination = startDestination
startDestination = Screen.Router.route
) {
composable(Screen.Language.route) {
LanguageScreen(navController)
}
composable(Screen.Login.route) {
LoginScreen(navController)
composable(Screen.Router.route) {
RouterScreen(navController)
}
composable(Screen.RequiredInfo.route) {
RequiredInfoScreen(navController)
}
composable(Screen.RequiredInfoComplete.route) {
RequiredInfoCompleteScreen(navController)
}
composable(
route = Screen.SignUp.route,
content = {
SignUpScreen(navController)
}
)

composable(Screen.Language.route) { LanguageScreen(navController) }
composable(Screen.Login.route) { LoginScreen(navController) }
composable(Screen.SignUp.route) { SignUpScreen(navController) }

composable(Screen.RequiredInfo.route) { RequiredInfoScreen(navController) }
composable(Screen.RequiredInfoComplete.route) { RequiredInfoCompleteScreen(navController) }

composable(Screen.PendingApproval.route) { PendingApprovalRouteScreen() }
composable(Screen.PendingConnecting.route) { PendingConnectingRouteScreen() }

//composable(Screen.Connected.route) { ConnectedPlaceholderScreen(navController) }
//composable(Screen.Blacklisted.route) { BlacklistedPlaceholderScreen(navController) }
}
}
62 changes: 62 additions & 0 deletions app/src/main/java/com/apptive/japkor/navigation/RouterScreen.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package com.apptive.japkor.navigation

import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalContext
import androidx.navigation.NavHostController
import com.apptive.japkor.data.local.DataStoreManager
import com.apptive.japkor.data.local.TokenProvider
import com.apptive.japkor.data.model.UserStatus
import kotlinx.coroutines.flow.first

@Composable
fun RouterScreen(
navController: NavHostController
) {
val context = LocalContext.current
val dataStore = remember {
DataStoreManager(context.applicationContext)
}

LaunchedEffect(Unit) {
val token = dataStore.getUserToken().first()

// 1️⃣ 토큰 없으면 → Language
if (token.isBlank()) {
navController.navigate(Screen.Language.route) {
popUpTo(Screen.Router.route) { inclusive = true }
}
return@LaunchedEffect
}

// 2️⃣ 토큰 있으면 메모리에 세팅
TokenProvider.setToken(token)

// 3️⃣ status 읽기
val statusStr = dataStore.getUserStatus().first()
val status = runCatching {
UserStatus.valueOf(statusStr)
}.getOrNull()

// 4️⃣ status → 목적지 결정
val targetRoute = when (status) {
UserStatus.INCOMPLETE_PROFILE -> Screen.RequiredInfo.route
UserStatus.PENDING_APPROVAL -> Screen.PendingApproval.route
UserStatus.APPROVED -> Screen.PendingConnecting.route
UserStatus.CONNECTING,
UserStatus.CONNECTED -> Screen.Connected.route
UserStatus.BLACKLISTED -> Screen.Blacklisted.route
null -> Screen.Login.route
}

// 5️⃣ Router 제거 + 이동
navController.navigate(targetRoute) {
popUpTo(Screen.Router.route) { inclusive = true }
launchSingleTop = true
}
}

// 👀 사용자에게 보이는 UI (간단한 로딩/스플래시)
//SplashLoadingScreen()
}
16 changes: 4 additions & 12 deletions app/src/main/java/com/apptive/japkor/ui/login/LoginScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -210,18 +210,10 @@ fun LoginScreen(navController: NavController,viewModel: LoginScreenViewModel = v
viewModel.signIn(email, password) { success, status ->
if (success) {
toastManager.success("로그인 성공! 환영합니다.")
when (status) {
UserStatus.INCOMPLETE_PROFILE -> {
navController.navigate(Screen.RequiredInfo.route)
}
UserStatus.PENDING_APPROVAL,
UserStatus.APPROVED,
UserStatus.CONNECTING,
UserStatus.CONNECTED,
UserStatus.BLACKLISTED -> {
navController.navigate(Screen.RequiredInfoComplete.route)
}
null -> navController.navigate(Screen.RequiredInfo.route)

navController.navigate(Screen.Router.route) {
popUpTo(Screen.Login.route) { inclusive = true }
launchSingleTop = true
}
} else {
toastManager.error("로그인 실패! 이메일과 비밀번호를 확인해주세요.")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,9 @@ fun RequiredInfoCompleteScreen(navController: NavController) {

Button(
onClick = {
navController.navigate(Screen.Language.route) {
popUpTo(Screen.Language.route) { inclusive = false }
navController.navigate(Screen.PendingApproval.route) {
popUpTo(Screen.RequiredInfoComplete.route) { inclusive = true }
launchSingleTop = true
}
},
modifier = Modifier.fillMaxWidth(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,16 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavController
import com.apptive.japkor.R
import com.apptive.japkor.data.local.DataStoreManager
import com.apptive.japkor.navigation.Screen
import com.apptive.japkor.ui.components.CustomText
import com.apptive.japkor.ui.components.CustomTextType
Expand All @@ -61,7 +65,17 @@ fun RequiredInfoScreen(
onSubmit: (name: String, email: String) -> Unit = { _, _ -> },
initialStep: Int = 1
) {
val requiredInfoViewModel: RequiredInfoViewModel = viewModel()
val context = LocalContext.current

val requiredInfoViewModel: RequiredInfoViewModel = viewModel(
factory = object : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return RequiredInfoViewModel(
dataStore = DataStoreManager(context.applicationContext)
) as T
}
}
)
val toastManager = LocalToastManager.current
val appLanguage = LocalAppLanguage.current

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ import android.provider.OpenableColumns
import android.util.Log
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.apptive.japkor.data.local.DataStoreManager
import com.apptive.japkor.data.model.PresignedUrlRequest
import com.apptive.japkor.data.model.RequiredInfoDTO
import com.apptive.japkor.data.model.UserStatus
import com.apptive.japkor.data.repository.ApiResult
import com.apptive.japkor.data.repository.RequiredInfoRepository
import com.apptive.japkor.ui.components.ToastType
Expand Down Expand Up @@ -46,6 +48,7 @@ sealed class RequiredInfoEvent {
}

class RequiredInfoViewModel(
private val dataStore: DataStoreManager,
private val repository: RequiredInfoRepository = RequiredInfoRepository()
) : ViewModel() {

Expand Down Expand Up @@ -418,6 +421,8 @@ class RequiredInfoViewModel(

if (result.success && result.code in 200..299) {
_submitState.value = SubmitState.Success
dataStore.saveUserName(name)
dataStore.saveUserStatus(UserStatus.PENDING_APPROVAL.name)
_events.emit(RequiredInfoEvent.NavigateToComplete)
} else {
val message = result.errorMessage ?: "알 수 없는 오류가 발생했습니다."
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.apptive.japkor.ui.status

import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalContext
import com.apptive.japkor.R
import com.apptive.japkor.data.local.DataStoreManager

@Composable
fun PendingApprovalRouteScreen() {
val context = LocalContext.current
val dataStore = remember { DataStoreManager(context.applicationContext) }

val name by dataStore.getUserName().collectAsState(initial = "")

PendingApprovalScreen(
name = name.ifBlank { "회원" },
logoRes = R.drawable.ampersand_bg
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.apptive.japkor.ui.status

import androidx.annotation.DrawableRes
import androidx.compose.runtime.Composable
import androidx.compose.ui.unit.dp

@Composable
fun PendingApprovalScreen(
name: String,
@DrawableRes logoRes: Int
) {
StatusWaitingTemplate(
name = name,
title = "프로필을 심사 중이에요!",
subtitle = "조금만 더 기다려주세요",
logoRes = logoRes,
logoOffsetX = (-150).dp // 왼쪽으로 밀기 (여기 값만 튜닝)
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.apptive.japkor.ui.status

import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalContext
import com.apptive.japkor.R
import com.apptive.japkor.data.local.DataStoreManager

@Composable
fun PendingConnectingRouteScreen() {
val context = LocalContext.current
val dataStore = remember { DataStoreManager(context.applicationContext) }

val name by dataStore.getUserName().collectAsState(initial = "")

PendingConnectingScreen(
name = name.ifBlank { "회원" },
logoRes = R.drawable.ampersand_bg
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.apptive.japkor.ui.status

import androidx.annotation.DrawableRes
import androidx.compose.runtime.Composable
import androidx.compose.ui.unit.dp

@Composable
fun PendingConnectingScreen(
name: String,
@DrawableRes logoRes: Int
) {
StatusWaitingTemplate(
name = name,
title = "매칭 상대를 찾고 있어요!",
subtitle = "조금만 더 기다려주세요",
logoRes = logoRes,
logoOffsetX = 150.dp, // 오른쪽으로 밀기 (여기 값만 튜닝)
)
}
Loading
Loading