tgyuuAn / BaekyoungE

์ž์—ฐ์–ด ์ฒ˜๋ฆฌ ๊ธฐ๋ฐ˜ ์ง„๋กœ ์ƒ๋‹ด chat bot ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜
5 stars 0 forks source link

Feature/#43 #44

Closed tgyuuAn closed 1 month ago

tgyuuAn commented 1 month ago

1. ๐Ÿ“„ ๊ด€๋ จ๋œ ์ด์Šˆ ๋ฐ ์†Œ๊ฐœ

์ด์Šˆ ํ•˜๋‚˜ ๋„ˆ๋ฌด ํฌ์ž–์•„ ํ•œ๋ฒˆ ๋จธ์ง€ ํ•˜๊ณ  ๊ฐ€~

2. ๐Ÿ”ฅ๋ณ€๊ฒฝ๋œ ์ 

3. ๐Ÿ“ธ ์Šคํฌ๋ฆฐ์ƒท(์„ ํƒ)

์ด์ „

Baekyoung ๋ชจ๋“ˆ ์˜์กด์„ฑ ๊ทธ๋ž˜ํ”„




๋ณ€๊ฒฝ

Baekyounge ๋ชจ๋“ˆ ์˜์กด์„ฑ ๊ทธ๋ž˜ํ”„ drawio




4. ๐Ÿ’ก์•Œ๊ฒŒ๋œ ํ˜น์€ ๊ถ๊ธˆํ•œ ์‚ฌํ•ญ๋“ค

๋’ค๋กœ๊ฐ€๊ธฐ๋กœ ๋Œ์•„์™”์„ ๋•Œ ๋ฐ์ดํ„ฐ๊ฐ€ ๊ฐฑ์‹  ์‹œํ‚ค๊ณ  ์‹ถ๋‹ค๊ตฌ์š”?

์ƒํ™ฉ

์ €์žฅ์†Œ ํ™”๋ฉด์—์„œ ์ฑ„ํŒ… ๊ธฐ๋ก์„ ๋“ค์–ด๊ฐ”๋‹ค๊ฐ€ ์ฑ„ํŒ…์„ ํ•˜๋‚˜ ์น˜๊ณ  ๋‚˜์˜จ ๋’ค, ์ €์žฅ์†Œ ํ™”๋ฉด์œผ๋กœ ๋Œ์•„์˜ค๋ฉด ์ƒˆ๋กœ์šด ๋ฐ์ดํ„ฐ๋กœ ๊ฐฑ์‹ ๋˜์–ด์•ผ ํ•˜๋Š”๋ฐ,

๊ธฐ์กด

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() ๋ฅผ ํ˜ธ์ถœํ•ด์•ผ ํ–ˆ์Œ.







ํ•ด๊ฒฐ์ฑ…

ํ•ด๊ฒฐ์ฑ… ๋งค์šฐ ๊ฐ„๋‹จํ–ˆ๋‹ค.

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,
    )
}

๊ทธ๋ƒฅ ๊ถ๊ธˆํ•ด์„œ ์ฐพ์•„๋ณธ... hiltViewModel()์„ ์‚ฌ์šฉํ•˜๋ฉด ์ƒ๋ช…์ฃผ๊ธฐ๊ฐ€ ์–ด๋–ป๊ฒŒ ๋˜๋Š”๋ฐ์š”?

image

์†ํ•˜๊ณ ์žˆ๋Š” navigationGraph์˜ ์ƒ๋ช…์ฃผ๊ธฐ๋ฅผ ๋”ฐ๋ผ๊ฐ„๋‹ค.




์ด ๋•Œ, hiltViewModel() ๋ง๊ณ ๋„ ์•„๋ž˜์™€ ๊ฐ™์ด viewModel() ๋กœ๋„ ๋ทฐ๋ชจ๋ธ์„ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ,

@Composable
MainScreen(
  viewModel: MainViewModel = viewModel()
)

์ด๋ ‡๊ฒŒ ๋  ๊ฒฝ์šฐ ํ•ด๋‹น MainScreen ์ด ํ˜ธ์ถœ๋  ๋•Œ๋งˆ๋‹ค ViewModel ์ธ์Šคํ„ด์Šค๊ฐ€ ์žฌ์ƒ์„ฑ๋œ๋‹ค.

๋ฐ˜๋ฉด, hiltViewModel()๋กœ ์ƒ์„ฑ๋œ viewModel์€ ์ƒ๋ช…์ฃผ๊ธฐ๊ฐ€ NavGraph์™€ ๊ฐ™๊ฒŒ ๋Œ.

๋ ˆํผ๋Ÿฐ์Šค







ModalDrawerSheet๋Š” ๊ธฐ๋ณธ๊ฐ’์ด ์™ผ์ชฝ -> ์˜ค๋ฅธ์ชฝ์œผ๋กœ ์—ด๋ฆฌ๋Š”๋ฐ ์–ด๋–ป๊ฒŒ ์˜ค๋ฅธ์ชฝ -> ์™ผ์ชฝ์œผ๋กœ ์—ด๋ฆฌ๊ฒŒ ํ• ๊ฑด๊ฐ€์š”?

์ด์ œ ์›๋ž˜๋Š” ์•„๋ž˜์ฒ˜๋Ÿผ ์™ผ์ชฝ -> ์˜ค๋ฅธ์ชฝ์œผ๋กœ ์—ด๋ฆฌ๋Š”๊ฒŒ default์ธ๋ฐ,

image




์ด์ œ ์šฐ๋ฆฌ๊ฐ€ ์›ํ•˜๋Š” ๊ฒƒ์€ ์นดํ†ก๋ฐฉ ์„œ๋ž์ฒ˜๋Ÿผ ์•„๋ž˜ ๊ทธ๋ฆผ์ด๊ฑธ๋ž‘์š”

image




์ด ๋•Œ๋Š”, ์•„๋ž˜ ์ฒ˜๋Ÿผ ์˜ค๋ฅธ์ชฝ์—์„œ ์™ผ์ชฝ์œผ๋กœ ์ฝํžˆ๋“ฏ์ด ์ œ๊ณตํ•˜๋Š” 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(







Android Modifier์— clicakble์„ ๋‹ฌ๋ฉด ripple ํšจ๊ณผ ๋ง˜์— ์•ˆ๋“œ๋Š”๋ฐ ์—†์• ๊ณ  ์‹ถ์–ด์š”

๋’ค์— ripple ๋‚˜์˜ค๋Š” ๊ฑฐ ๋„ˆ๋ฌด ๊ตฌ๋ ค์š” ์—†์• ์ฃผ์„ธ์š”.




clickable ํ•จ์ˆ˜๋Š” ๋‘ ๊ฐ€์ง€ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์˜ค๋ฒ„๋กœ๋”ฉ์ด ๋˜์–ด์žˆ๋Š”๋ฐ,

์ด ๋•Œ ๊นŒ์ง€ ์ฃผ๋กœ ์œ„ ํ•จ์ˆ˜๋กœ ์‚ฌ์šฉํ–ˆ์ง€๋งŒ,

ํด๋ฆญ ์‹œ ripple ํšจ๊ณผ๋ฅผ ์ œ๊ฑฐ ํ˜น์€ ๋‹ค๋ฅธ ํšจ๊ณผ๋กœ ๋ณ€๊ฒฝ ํ•˜๊ณ  ์‹ถ์„ ๊ฒฝ์šฐ ๋ฐ‘์˜ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.







์•„๋ž˜์™€ ๊ฐ™์ด indiciation์— null์„ ๋„ฃ์–ด์ฃผ๋ฉด ๋˜๋Š”๋ฐ, ์ด ๋•Œ ์•„๋ž˜ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” interactionSource๊ฐ€ ํ•„์ˆ˜์ ์œผ๋กœ ๋“ค์–ด๊ฐ€์•ผํ•˜๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ์ด๊ธฐ ๋•Œ๋ฌธ์— ์•„๋ž˜์ฒ˜๋Ÿผ ํ•ด์ฃผ๋ฉด ๋!!!

modifier = Modifier.clickable(
    interactionSource = remember { MutableInteractionSource() },
    indication = null,
) {
    // Todo             
},

๋ ˆํผ๋Ÿฐ์Šค 1 ๋ ˆํผ๋Ÿฐ์Šค 2