Closed tgyuuAn closed 6 months ago
์ด์ ํ๋ ๋๋ฌด ํฌ์์ ํ๋ฒ ๋จธ์ง ํ๊ณ ๊ฐ~
์ด์
๋ณ๊ฒฝ
์ ์ฅ์ ํ๋ฉด์์ ์ฑํ ๊ธฐ๋ก์ ๋ค์ด๊ฐ๋ค๊ฐ ์ฑํ ์ ํ๋ ์น๊ณ ๋์จ ๋ค, ์ ์ฅ์ ํ๋ฉด์ผ๋ก ๋์์ค๋ฉด ์๋ก์ด ๋ฐ์ดํฐ๋ก ๊ฐฑ์ ๋์ด์ผ ํ๋๋ฐ,
backstack()์ผ๋ก ๋์์๊ธฐ ๋๋ฌธ์ ์๋กญ๊ฒ ๋ฐ์ดํฐ๋ฅผ ํธ์ถํ๋ ๋ก์ง์ ๋ฃ๊ธฐ ํ๋ค์์.
backstack()
// StorageScreen @Composable internal fun StorageRoute( navigateToChatting: (String) -> Unit, viewModel: StorageViewModel = hiltViewModel(), ) { val selectedYear by viewModel.selectedYear.collectAsStateWithLifecycle() val chattingRooms by viewModel.chattingLogs.collectAsStateWithLifecycle() val yearPickerState = rememberFWheelPickerState() val (showChatLogDeleteDialog, setChatLogDeleteDialog) = remember { mutableStateOf(false) } val snackbarHostState = remember { SnackbarHostState() } LaunchedEffect(true) { viewModel.eventFlow.collectLatest { event -> when (event) { is StorageViewModel.StorageEvent.DeleteSuccess -> setChatLogDeleteDialog(false) is StorageViewModel.StorageEvent.EventFailed -> snackbarHostState.showSnackbar(event.message) } } } StorageScreen( snackbarHostState = snackbarHostState, selectedYear = selectedYear, chattingRooms = chattingRooms, yearPickerState = yearPickerState, showChatLogDeleteDialog = showChatLogDeleteDialog, setChatLogDeleteDialog = setChatLogDeleteDialog, deleteChattingRoom = viewModel::deleteChattingRoom, navigateToChatting = navigateToChatting, ) } // StorageViewModel Inject constructor( private val getAllChattingLogUseCase: GetAllChattingLogUseCase, private val deleteChattingRoomUseCase: DeleteChattingRoomUseCase, ) : ViewModel() { private val _eventFlow = MutableSharedFlow<StorageEvent>() val eventFlow = _eventFlow.asSharedFlow() private val _selectedYear = MutableStateFlow("2024") val selectedYear = _selectedYear.asStateFlow() private val _chattingLogs = MutableStateFlow<List<ChattingRoom>>(listOf()) val chattingLogs = _chattingLogs.asStateFlow() init { getAllChattingLogs() } fun event(event: StorageEvent) = viewModelScope.launch { _eventFlow.emit(event) } private fun getAllChattingLogs() = viewModelScope.launch { getAllChattingLogUseCase() .onSuccess { _chattingLogs.value = it } .onFailure { event(StorageEvent.EventFailed(it.toString())) } }
์ฆ, popBackStack()์ผ๋ก ๋์์ค๋๋ผ๋ ViewModel init ๋ธ๋ญ์ ์๋ getAllChattingLogs() ๋ฅผ ํธ์ถํด์ผ ํ์.
popBackStack()
getAllChattingLogs()
ํด๊ฒฐ์ฑ ๋งค์ฐ ๊ฐ๋จํ๋ค.
ViewModel์ init ์์ ํธ์ถํ๋ ๋ก์ง์ StorageRouet์ LaunchedEffect()์์ ํธ์ถํ๋๋ก ๋ณ๊ฒฝํ๋ฉด ๋์์. ํฌํฌ
@Composable internal fun StorageRoute( navigateToChatting: (String) -> Unit, viewModel: StorageViewModel = hiltViewModel(), ) { val selectedYear by viewModel.selectedYear.collectAsStateWithLifecycle() val chattingRooms by viewModel.chattingLogs.collectAsStateWithLifecycle() val yearPickerState = rememberFWheelPickerState() val (showChatLogDeleteDialog, setChatLogDeleteDialog) = remember { mutableStateOf(false) } val snackbarHostState = remember { SnackbarHostState() } LaunchedEffect(true) { viewModel.getAllChattingLogs() viewModel.eventFlow.collectLatest { event -> when (event) { is StorageViewModel.StorageEvent.DeleteSuccess -> setChatLogDeleteDialog(false) is StorageViewModel.StorageEvent.EventFailed -> snackbarHostState.showSnackbar(event.message) } } } StorageScreen( snackbarHostState = snackbarHostState, selectedYear = selectedYear, chattingRooms = chattingRooms, yearPickerState = yearPickerState, showChatLogDeleteDialog = showChatLogDeleteDialog, setChatLogDeleteDialog = setChatLogDeleteDialog, deleteChattingRoom = viewModel::deleteChattingRoom, navigateToChatting = navigateToChatting, ) }
์ํ๊ณ ์๋ navigationGraph์ ์๋ช ์ฃผ๊ธฐ๋ฅผ ๋ฐ๋ผ๊ฐ๋ค.
์ด ๋, hiltViewModel() ๋ง๊ณ ๋ ์๋์ ๊ฐ์ด viewModel() ๋ก๋ ๋ทฐ๋ชจ๋ธ์ ์์ฑํ ์ ์๋๋ฐ,
hiltViewModel()
viewModel()
@Composable MainScreen( viewModel: MainViewModel = viewModel() )
์ด๋ ๊ฒ ๋ ๊ฒฝ์ฐ ํด๋น MainScreen ์ด ํธ์ถ๋ ๋๋ง๋ค ViewModel ์ธ์คํด์ค๊ฐ ์ฌ์์ฑ๋๋ค.
MainScreen
๋ฐ๋ฉด, hiltViewModel()๋ก ์์ฑ๋ viewModel์ ์๋ช ์ฃผ๊ธฐ๊ฐ NavGraph์ ๊ฐ๊ฒ ๋.
๋ ํผ๋ฐ์ค
์ด์ ์๋๋ ์๋์ฒ๋ผ ์ผ์ชฝ -> ์ค๋ฅธ์ชฝ์ผ๋ก ์ด๋ฆฌ๋๊ฒ default์ธ๋ฐ,
์ด์ ์ฐ๋ฆฌ๊ฐ ์ํ๋ ๊ฒ์ ์นดํก๋ฐฉ ์๋์ฒ๋ผ ์๋ ๊ทธ๋ฆผ์ด๊ฑธ๋์
์ด ๋๋, ์๋ ์ฒ๋ผ ์ค๋ฅธ์ชฝ์์ ์ผ์ชฝ์ผ๋ก ์ฝํ๋ฏ์ด ์ ๊ณตํ๋ layoutDirection์ ๊ฐ์ ๋ก Rtl๋ก ๋ฐ๊ฟ์ ์ฐํํด์ ๊ตฌํ๊ฐ๋ฅ....!
๋ ํผ๋ฐ์ค 1 ๋ ํผ๋ฐ์ค 2
CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Rtl) { ModalNavigationDrawer( drawerState = drawerState, drawerContent = { CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr) { Column( modifier = Modifier .background(BaekyoungTheme.colors.white) .width((localConfiguration.screenWidthDp.dp * 3) / 4), ) { Text(
๋ค์ ripple ๋์ค๋ ๊ฑฐ ๋๋ฌด ๊ตฌ๋ ค์ ์์ ์ฃผ์ธ์.
clickable ํจ์๋ ๋ ๊ฐ์ง ํ๋ผ๋ฏธํฐ๋ก ์ค๋ฒ๋ก๋ฉ์ด ๋์ด์๋๋ฐ,
clickable
์ด ๋ ๊น์ง ์ฃผ๋ก ์ ํจ์๋ก ์ฌ์ฉํ์ง๋ง,
ํด๋ฆญ ์ ripple ํจ๊ณผ๋ฅผ ์ ๊ฑฐ ํน์ ๋ค๋ฅธ ํจ๊ณผ๋ก ๋ณ๊ฒฝ ํ๊ณ ์ถ์ ๊ฒฝ์ฐ ๋ฐ์ ํจ์๋ฅผ ์ฌ์ฉํด์ผ ํ๋ค.
์๋์ ๊ฐ์ด indiciation์ null์ ๋ฃ์ด์ฃผ๋ฉด ๋๋๋ฐ, ์ด ๋ ์๋ ํจ์๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด์๋ interactionSource๊ฐ ํ์์ ์ผ๋ก ๋ค์ด๊ฐ์ผํ๋ ํ๋ผ๋ฏธํฐ์ด๊ธฐ ๋๋ฌธ์ ์๋์ฒ๋ผ ํด์ฃผ๋ฉด ๋!!!
indiciation
interactionSource
modifier = Modifier.clickable( interactionSource = remember { MutableInteractionSource() }, indication = null, ) { // Todo },
1. ๐ ๊ด๋ จ๋ ์ด์ ๋ฐ ์๊ฐ
43
์ด์ ํ๋ ๋๋ฌด ํฌ์์ ํ๋ฒ ๋จธ์ง ํ๊ณ ๊ฐ~
2. ๐ฅ๋ณ๊ฒฝ๋ ์
3. ๐ธ ์คํฌ๋ฆฐ์ท(์ ํ)
์ด์
๋ณ๊ฒฝ
4. ๐ก์๊ฒ๋ ํน์ ๊ถ๊ธํ ์ฌํญ๋ค
๋ค๋ก๊ฐ๊ธฐ๋ก ๋์์์ ๋ ๋ฐ์ดํฐ๊ฐ ๊ฐฑ์ ์ํค๊ณ ์ถ๋ค๊ตฌ์?
์ํฉ
์ ์ฅ์ ํ๋ฉด์์ ์ฑํ ๊ธฐ๋ก์ ๋ค์ด๊ฐ๋ค๊ฐ ์ฑํ ์ ํ๋ ์น๊ณ ๋์จ ๋ค, ์ ์ฅ์ ํ๋ฉด์ผ๋ก ๋์์ค๋ฉด ์๋ก์ด ๋ฐ์ดํฐ๋ก ๊ฐฑ์ ๋์ด์ผ ํ๋๋ฐ,
๊ธฐ์กด
backstack()
์ผ๋ก ๋์์๊ธฐ ๋๋ฌธ์ ์๋กญ๊ฒ ๋ฐ์ดํฐ๋ฅผ ํธ์ถํ๋ ๋ก์ง์ ๋ฃ๊ธฐ ํ๋ค์์.์ฆ,
popBackStack()
์ผ๋ก ๋์์ค๋๋ผ๋ ViewModel init ๋ธ๋ญ์ ์๋getAllChattingLogs()
๋ฅผ ํธ์ถํด์ผ ํ์.ํด๊ฒฐ์ฑ
ํด๊ฒฐ์ฑ ๋งค์ฐ ๊ฐ๋จํ๋ค.
ViewModel์ init ์์ ํธ์ถํ๋ ๋ก์ง์ StorageRouet์ LaunchedEffect()์์ ํธ์ถํ๋๋ก ๋ณ๊ฒฝํ๋ฉด ๋์์. ํฌํฌ
๊ทธ๋ฅ ๊ถ๊ธํด์ ์ฐพ์๋ณธ... hiltViewModel()์ ์ฌ์ฉํ๋ฉด ์๋ช ์ฃผ๊ธฐ๊ฐ ์ด๋ป๊ฒ ๋๋๋ฐ์?
์ํ๊ณ ์๋ navigationGraph์ ์๋ช ์ฃผ๊ธฐ๋ฅผ ๋ฐ๋ผ๊ฐ๋ค.
์ด ๋,
hiltViewModel()
๋ง๊ณ ๋ ์๋์ ๊ฐ์ดviewModel()
๋ก๋ ๋ทฐ๋ชจ๋ธ์ ์์ฑํ ์ ์๋๋ฐ,์ด๋ ๊ฒ ๋ ๊ฒฝ์ฐ ํด๋น
MainScreen
์ด ํธ์ถ๋ ๋๋ง๋ค ViewModel ์ธ์คํด์ค๊ฐ ์ฌ์์ฑ๋๋ค.๋ฐ๋ฉด,
hiltViewModel()
๋ก ์์ฑ๋ viewModel์ ์๋ช ์ฃผ๊ธฐ๊ฐ NavGraph์ ๊ฐ๊ฒ ๋.๋ ํผ๋ฐ์ค
ModalDrawerSheet๋ ๊ธฐ๋ณธ๊ฐ์ด ์ผ์ชฝ -> ์ค๋ฅธ์ชฝ์ผ๋ก ์ด๋ฆฌ๋๋ฐ ์ด๋ป๊ฒ ์ค๋ฅธ์ชฝ -> ์ผ์ชฝ์ผ๋ก ์ด๋ฆฌ๊ฒ ํ ๊ฑด๊ฐ์?
์ด์ ์๋๋ ์๋์ฒ๋ผ ์ผ์ชฝ -> ์ค๋ฅธ์ชฝ์ผ๋ก ์ด๋ฆฌ๋๊ฒ default์ธ๋ฐ,
์ด์ ์ฐ๋ฆฌ๊ฐ ์ํ๋ ๊ฒ์ ์นดํก๋ฐฉ ์๋์ฒ๋ผ ์๋ ๊ทธ๋ฆผ์ด๊ฑธ๋์
์ด ๋๋, ์๋ ์ฒ๋ผ ์ค๋ฅธ์ชฝ์์ ์ผ์ชฝ์ผ๋ก ์ฝํ๋ฏ์ด ์ ๊ณตํ๋ layoutDirection์ ๊ฐ์ ๋ก Rtl๋ก ๋ฐ๊ฟ์ ์ฐํํด์ ๊ตฌํ๊ฐ๋ฅ....!
๋ ํผ๋ฐ์ค 1 ๋ ํผ๋ฐ์ค 2
Android Modifier์ clicakble์ ๋ฌ๋ฉด ripple ํจ๊ณผ ๋ง์ ์๋๋๋ฐ ์์ ๊ณ ์ถ์ด์
๋ค์ ripple ๋์ค๋ ๊ฑฐ ๋๋ฌด ๊ตฌ๋ ค์ ์์ ์ฃผ์ธ์.
clickable
ํจ์๋ ๋ ๊ฐ์ง ํ๋ผ๋ฏธํฐ๋ก ์ค๋ฒ๋ก๋ฉ์ด ๋์ด์๋๋ฐ,์ด ๋ ๊น์ง ์ฃผ๋ก ์ ํจ์๋ก ์ฌ์ฉํ์ง๋ง,
ํด๋ฆญ ์ ripple ํจ๊ณผ๋ฅผ ์ ๊ฑฐ ํน์ ๋ค๋ฅธ ํจ๊ณผ๋ก ๋ณ๊ฒฝ ํ๊ณ ์ถ์ ๊ฒฝ์ฐ ๋ฐ์ ํจ์๋ฅผ ์ฌ์ฉํด์ผ ํ๋ค.
์๋์ ๊ฐ์ด
indiciation
์ null์ ๋ฃ์ด์ฃผ๋ฉด ๋๋๋ฐ, ์ด ๋ ์๋ ํจ์๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด์๋interactionSource
๊ฐ ํ์์ ์ผ๋ก ๋ค์ด๊ฐ์ผํ๋ ํ๋ผ๋ฏธํฐ์ด๊ธฐ ๋๋ฌธ์ ์๋์ฒ๋ผ ํด์ฃผ๋ฉด ๋!!!๋ ํผ๋ฐ์ค 1 ๋ ํผ๋ฐ์ค 2