Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Base] #25 app navigation 구현 #30

Merged
merged 3 commits into from
Aug 3, 2024
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
13 changes: 13 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,11 @@ dependencies {
implementation(project(":core:ui"))
implementation(project(":data"))
implementation(project(":domain"))
implementation(project(":feature:addlink"))
implementation(project(":feature:addpokit"))
implementation(project(":feature:login"))
implementation(project(":feature:pokitdetail"))
implementation(project(":feature:search"))

// hilt
implementation(libs.hilt)
Expand All @@ -81,4 +85,13 @@ dependencies {
// firebase
implementation(platform(libs.firebase.bom))
implementation(libs.firebase.auth.ktx)

// navigation
implementation(libs.androidx.navigation.compose)
implementation(libs.hilt.navigation.compose)

// orbit
implementation(libs.orbit.compose)
implementation(libs.orbit.core)
implementation(libs.orbit.viewmodel)
}
20 changes: 18 additions & 2 deletions app/src/main/java/pokitmons/pokit/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,33 @@ package pokitmons.pokit
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController
import dagger.hilt.android.AndroidEntryPoint
import pokitmons.pokit.core.ui.theme.PokitTheme
import pokitmons.pokit.navigation.LoginNavHost
import pokitmons.pokit.navigation.RootNavHost

@AndroidEntryPoint
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
PokitTheme {
LoginNavHost()
val navHostController = rememberNavController()
val navBackStackEntry by navHostController.currentBackStackEntryAsState()
val currentDestination by remember(navBackStackEntry) { derivedStateOf { navBackStackEntry?.destination } }

LaunchedEffect(currentDestination) {
currentDestination?.route?.let { route ->
// 믹스패널/파베 애널리틱스 화면 이동 로깅용
}
Comment on lines +26 to +29
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

믹스패널 고려까지 알잘딱깔센;;

}

RootNavHost(navHostController = navHostController)
}
}
}
Expand Down
47 changes: 47 additions & 0 deletions app/src/main/java/pokitmons/pokit/navigation/RootDestination.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package pokitmons.pokit.navigation

import androidx.navigation.NavType
import androidx.navigation.navArgument

object Login {
val route: String = "login"
}

object Home {
val route: String = "home"
}

object AddLink {
val route: String = "addLink"
val linkIdArg = "link_id"
val routeWithArgs = "$route?$linkIdArg={$linkIdArg}"
var arguments = listOf(
navArgument(linkIdArg) {
nullable = true
type = NavType.StringType
}
)
}

object AddPokit {
val route: String = "addPokit"
val pokitIdArg = "pokit_id"
val routeWithArgs = "$route?$pokitIdArg={$pokitIdArg}"
var arguments = listOf(
navArgument(pokitIdArg) {
nullable = true
type = NavType.StringType
}
)
}
Comment on lines +14 to +36
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

요 부분 이해안가는데 설명 부탁드립니답

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

일반적으로 navigation 호출할 때, 인자를 넘겨줄 필요가 없다면 형이 login쪽 구현했던 방식처럼

sealed class LoginRoute(val name: String) {
    data object LoginScreen : LoginRoute("LoginScreen")
    // ~~
}

이렇게 구현하면 되는데, 만약 인자가 필요한 경우에는 그 인자 정보까지 route 경로에 포함을 시켜줘야 돼
위 경우에는 linkIdArg가 있으면 링크 수정/없으면 링크 추가 화면으로 사용되기 때문에 linkIdArg가 선택인자이고, 그렇기 때문에 해당 인자를 nullable하게 설정하고, 그 인자 정보까지 반영된 routeWithArgs를 사용하는 거야


object PokitDetail {
val route: String = "pokitDetail"
val pokitIdArg = "pokit_id"
val routeWithArgs = "$route/{$pokitIdArg}"
var arguments = listOf(navArgument(pokitIdArg) { defaultValue = "-" })
}
Comment on lines +38 to +43
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

요 부분 이해안가는데 설명 부탁드립니답 22

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여기서는 pokitIdArg가 반드시 필요한 정보기 때문데 ?가 아닌 일반 세부 경로 선언하듯 /를 사용해서 인자 정보를 반영한 routeWithArgs를 선언한 거야

다 적고 보니까 설명을 잘 못한 거 같아서 이와 관련된 공식 문서 링크 달아둘께!


object Search {
val route: String = "search"
}
96 changes: 96 additions & 0 deletions app/src/main/java/pokitmons/pokit/navigation/RootNavHost.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package pokitmons.pokit.navigation

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import com.strayalpaca.addlink.AddLinkScreenContainer
import com.strayalpaca.addlink.AddLinkViewModel
import com.strayalpaca.addpokit.AddPokitScreenContainer
import com.strayalpaca.addpokit.AddPokitViewModel
import com.strayalpaca.pokitdetail.PokitDetailScreenContainer
import com.strayalpaca.pokitdetail.PokitDetailViewModel
import pokitmons.pokit.LoginViewModel
import pokitmons.pokit.login.LoginScreen
import pokitmons.pokit.search.SearchScreenContainer
import pokitmons.pokit.search.SearchViewModel

@Composable
fun RootNavHost(
navHostController: NavHostController,
) {
NavHost(navController = navHostController, startDestination = Login.route) {
composable(Login.route) {
val viewModel: LoginViewModel = hiltViewModel()
LoginScreen(
loginViewModel = viewModel,
onNavigateToTermsOfServiceScreen = {}
)
}

composable(Home.route) {
Box(modifier = Modifier.fillMaxSize())
}

composable(
route = AddLink.routeWithArgs,
arguments = AddLink.arguments
) { navBackStackEntry ->
val viewModel: AddLinkViewModel = hiltViewModel()
val linkId = navBackStackEntry.arguments?.getString(AddLink.linkIdArg)
AddLinkScreenContainer(
linkId = linkId,
viewModel = viewModel,
onBackPressed = navHostController::popBackStack,
onNavigateToAddPokit = {
navHostController.navigate(AddPokit.route)
}
)
}

composable(
route = AddPokit.routeWithArgs,
arguments = AddPokit.arguments
) {
val viewModel: AddPokitViewModel = hiltViewModel()
AddPokitScreenContainer(
viewModel = viewModel,
onBackPressed = navHostController::popBackStack
)
}

composable(
route = PokitDetail.routeWithArgs,
arguments = PokitDetail.arguments
) {
val viewModel: PokitDetailViewModel = hiltViewModel()
PokitDetailScreenContainer(
viewModel = viewModel,
onBackPressed = navHostController::popBackStack,
onNavigateToLinkModify = { linkId ->
navHostController.navigate("${AddLink.route}?${AddLink.linkIdArg}=$linkId")
},
onNavigateToPokitModify = { pokitId ->
navHostController.navigate("${AddPokit.route}?${AddPokit.pokitIdArg}=$pokitId")
}
)
}

composable(
route = Search.route
) {
val viewModel: SearchViewModel = hiltViewModel()
SearchScreenContainer(
viewModel = viewModel,
onBackPressed = navHostController::popBackStack,
onNavigateToLinkModify = { linkId ->
navHostController.navigate("${AddLink.route}?${AddLink.linkIdArg}=$linkId")
}
)
}
}
}
6 changes: 6 additions & 0 deletions feature/addlink/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
plugins {
alias(libs.plugins.com.android.library)
alias(libs.plugins.org.jetbrains.kotlin.android)
alias(libs.plugins.hilt)
id("kotlin-kapt")
}

android {
Expand Down Expand Up @@ -60,5 +62,9 @@ dependencies {
implementation(libs.orbit.core)
implementation(libs.orbit.viewmodel)

// hilt
implementation(libs.hilt)
kapt(libs.hilt.compiler)

implementation(project(":core:ui"))
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ fun AddLinkScreenContainer(
linkId: String?,
viewModel: AddLinkViewModel,
onBackPressed: () -> Unit,
onNavigateToAddPokit: () -> Unit,
) {
val state by viewModel.collectAsState()
val context = LocalContext.current
Expand Down Expand Up @@ -100,7 +101,7 @@ fun AddLinkScreenContainer(
inputTitle = viewModel::inputTitle,
inputMemo = viewModel::inputMemo,
inputNewPokitName = viewModel::inputNewPokitName,
onClickAddPokit = viewModel::showAddPokitBottomSheet,
onClickAddPokit = onNavigateToAddPokit,
onClickSavePokit = viewModel::savePokit,
dismissPokitAddBottomSheet = viewModel::hideAddPokitBottomSheet,
onClickSelectPokit = viewModel::showSelectPokitBottomSheet,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import com.strayalpaca.addlink.model.Pokit
import com.strayalpaca.addlink.model.ScreenStep
import com.strayalpaca.addlink.model.sampleLink
import com.strayalpaca.addlink.model.samplePokitList
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
Expand All @@ -22,8 +23,10 @@ import org.orbitmvi.orbit.syntax.simple.intent
import org.orbitmvi.orbit.syntax.simple.postSideEffect
import org.orbitmvi.orbit.syntax.simple.reduce
import org.orbitmvi.orbit.viewmodel.container
import javax.inject.Inject

class AddLinkViewModel : ContainerHost<AddLinkScreenState, AddLinkScreenSideEffect>, ViewModel() {
@HiltViewModel
class AddLinkViewModel @Inject constructor() : ContainerHost<AddLinkScreenState, AddLinkScreenSideEffect>, ViewModel() {
override val container: Container<AddLinkScreenState, AddLinkScreenSideEffect> = container(AddLinkScreenState())

private val _linkUrl = MutableStateFlow("")
Expand Down
6 changes: 6 additions & 0 deletions feature/addpokit/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
plugins {
alias(libs.plugins.com.android.library)
alias(libs.plugins.org.jetbrains.kotlin.android)
alias(libs.plugins.hilt)
id("kotlin-kapt")
}

android {
Expand Down Expand Up @@ -60,5 +62,9 @@ dependencies {
implementation(libs.orbit.core)
implementation(libs.orbit.viewmodel)

// hilt
implementation(libs.hilt)
kapt(libs.hilt.compiler)

implementation(project(":core:ui"))
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import com.strayalpaca.addpokit.model.AddPokitSideEffect
import com.strayalpaca.addpokit.model.PokitInputErrorMessage
import com.strayalpaca.addpokit.model.PokitProfile
import com.strayalpaca.addpokit.model.samplePokitList
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
Expand All @@ -21,8 +22,10 @@ import org.orbitmvi.orbit.syntax.simple.intent
import org.orbitmvi.orbit.syntax.simple.postSideEffect
import org.orbitmvi.orbit.syntax.simple.reduce
import org.orbitmvi.orbit.viewmodel.container
import javax.inject.Inject

class AddPokitViewModel : ContainerHost<AddPokitScreenState, AddPokitSideEffect>, ViewModel() {
@HiltViewModel
class AddPokitViewModel @Inject constructor() : ContainerHost<AddPokitScreenState, AddPokitSideEffect>, ViewModel() {
override val container: Container<AddPokitScreenState, AddPokitSideEffect> = container(AddPokitScreenState())

private val _pokitName = MutableStateFlow("")
Expand Down
6 changes: 6 additions & 0 deletions feature/pokitdetail/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
plugins {
alias(libs.plugins.com.android.library)
alias(libs.plugins.org.jetbrains.kotlin.android)
alias(libs.plugins.hilt)
id("kotlin-kapt")
}

android {
Expand Down Expand Up @@ -60,5 +62,9 @@ dependencies {
implementation(libs.orbit.core)
implementation(libs.orbit.viewmodel)

// hilt
implementation(libs.hilt)
kapt(libs.hilt.compiler)

implementation(project(":core:ui"))
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import androidx.compose.material3.HorizontalDivider
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
Expand All @@ -38,6 +39,8 @@ import pokitmons.pokit.core.ui.R.drawable as coreDrawable
fun PokitDetailScreenContainer(
viewModel: PokitDetailViewModel,
onBackPressed: () -> Unit,
onNavigateToLinkModify: (String) -> Unit,
onNavigateToPokitModify: (String) -> Unit,
) {
val state by viewModel.state.collectAsState()
val linkList by viewModel.linkList.collectAsState()
Expand All @@ -61,7 +64,9 @@ fun PokitDetailScreenContainer(
state = state,
linkList = linkList,
pokitList = pokitList,
onClickLink = viewModel::showLinkDetailBottomSheet
onClickLink = viewModel::showLinkDetailBottomSheet,
onClickPokitModify = onNavigateToLinkModify,
onClickLinkModify = onNavigateToPokitModify
)
}

Expand All @@ -85,6 +90,8 @@ fun PokitDetailScreen(
linkList: List<Link> = emptyList(),
pokitList: List<Pokit> = emptyList(),
onClickLink: (Link) -> Unit = {},
onClickPokitModify: (String) -> Unit = {},
onClickLinkModify: (String) -> Unit = {},
) {
Column(
modifier = Modifier.fillMaxSize()
Expand Down Expand Up @@ -169,7 +176,14 @@ fun PokitDetailScreen(
BottomSheetType.MODIFY -> {
ModifyBottomSheetContent(
onClickShare = {},
onClickModify = {},
onClickModify = remember {
{
state.currentLink?.let { link ->
hideLinkModifyBottomSheet()
onClickLinkModify(link.id)
}
}
},
onClickRemove = showLinkRemoveBottomSheet
)
}
Expand All @@ -195,7 +209,12 @@ fun PokitDetailScreen(
BottomSheetType.MODIFY -> {
ModifyBottomSheetContent(
onClickShare = {},
onClickModify = {},
onClickModify = remember {
{
hidePokitModifyBottomSheet()
onClickPokitModify(state.currentPokit.id)
}
},
onClickRemove = showPokitRemoveBottomSheet
)
}
Expand Down
Loading
Loading