From 0c79ae49b12e781d43afca1004e29f206ad1a12d Mon Sep 17 00:00:00 2001 From: arinming Date: Sat, 14 Sep 2024 23:42:38 +0900 Subject: [PATCH 01/14] =?UTF-8?q?[FIX/#250]=20=ED=83=90=EC=83=89=20?= =?UTF-8?q?=EB=B7=B0=20=ED=85=8D=EC=8A=A4=ED=8A=B8=ED=95=84=EB=93=9C=20?= =?UTF-8?q?=ED=85=8D=EC=8A=A4=ED=8A=B8=EC=8A=A4=ED=83=80=EC=9D=BC=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/designsystem/component/textfield/SearchTextField.kt | 4 +++- .../java/com/terning/feature/search/search/SearchRoute.kt | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/com/terning/core/designsystem/component/textfield/SearchTextField.kt b/core/src/main/java/com/terning/core/designsystem/component/textfield/SearchTextField.kt index f030ccec4..1fd0590b3 100644 --- a/core/src/main/java/com/terning/core/designsystem/component/textfield/SearchTextField.kt +++ b/core/src/main/java/com/terning/core/designsystem/component/textfield/SearchTextField.kt @@ -5,6 +5,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.SolidColor import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.platform.LocalSoftwareKeyboardController +import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.input.ImeAction import com.terning.core.designsystem.theme.Grey300 import com.terning.core.designsystem.theme.Grey400 @@ -27,6 +28,7 @@ import com.terning.core.designsystem.theme.TerningTheme @Composable fun SearchTextField( text: String = "", + textStyle: TextStyle = TerningTheme.typography.body2, onValueChange: (String) -> Unit = {}, modifier: Modifier, hint: String, @@ -42,7 +44,7 @@ fun SearchTextField( value = text, onValueChange = onValueChange, modifier = modifier, - textStyle = TerningTheme.typography.button3, + textStyle = textStyle, textColor = Grey400, cursorBrush = SolidColor(Grey300), drawLineColor = TerningMain, diff --git a/feature/src/main/java/com/terning/feature/search/search/SearchRoute.kt b/feature/src/main/java/com/terning/feature/search/search/SearchRoute.kt index 1088e226c..28cb9804e 100644 --- a/feature/src/main/java/com/terning/feature/search/search/SearchRoute.kt +++ b/feature/src/main/java/com/terning/feature/search/search/SearchRoute.kt @@ -114,6 +114,7 @@ fun SearchScreen( } ) { SearchTextField( + textStyle = TerningTheme.typography.detail2, hint = stringResource(R.string.search_text_field_hint), leftIcon = R.drawable.ic_nav_search, modifier = Modifier.fillMaxWidth(), From 07eaaaf7637b0f8dead4cad87691390b39089ecb Mon Sep 17 00:00:00 2001 From: arinming Date: Sat, 14 Sep 2024 23:48:44 +0900 Subject: [PATCH 02/14] =?UTF-8?q?[FIX/#250]=20=ED=83=90=EC=83=89=20?= =?UTF-8?q?=EB=B7=B0=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20=ED=98=95=EC=8B=9D=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/response/SearchResultResponseDto.kt | 20 ++++++++++--------- .../data/mapper/search/SearchResultMapper.kt | 2 +- .../domain/entity/search/SearchResult.kt | 4 ++-- .../searchprocess/SearchProcessRoute.kt | 6 +++--- .../searchprocess/SearchProcessViewModel.kt | 1 - 5 files changed, 17 insertions(+), 16 deletions(-) diff --git a/data/src/main/java/com/terning/data/dto/response/SearchResultResponseDto.kt b/data/src/main/java/com/terning/data/dto/response/SearchResultResponseDto.kt index 14e7e4bf2..2ce61a3b8 100644 --- a/data/src/main/java/com/terning/data/dto/response/SearchResultResponseDto.kt +++ b/data/src/main/java/com/terning/data/dto/response/SearchResultResponseDto.kt @@ -7,6 +7,8 @@ import kotlinx.serialization.Serializable data class SearchResultResponseDto( @SerialName("totalPages") val totalPages: Int, + @SerialName("totalCount") + val totalCount: Int, @SerialName("hasNext") val hasNext: Boolean, @SerialName("announcements") @@ -16,21 +18,21 @@ data class SearchResultResponseDto( data class SearchAnnouncementDto( @SerialName("internshipAnnouncementId") val internshipAnnouncementId: Long, - @SerialName("scrapId") - val scrapId: Long?, - @SerialName("dDay") - val dDay: String, - @SerialName("companyImage") - val companyImage: String, @SerialName("title") val title: String, + @SerialName("dDay") + val dDay: String, @SerialName("workingPeriod") val workingPeriod: String, + @SerialName("companyImage") + val companyImage: String, + @SerialName("isScrapped") + val isScrapped: Boolean, + @SerialName("deadline") + val deadline: String, @SerialName("startYearMonth") val startYearMonth: String, @SerialName("color") val color: String?, - @SerialName("deadline") - val deadline: String, ) -} \ No newline at end of file +} diff --git a/data/src/main/java/com/terning/data/mapper/search/SearchResultMapper.kt b/data/src/main/java/com/terning/data/mapper/search/SearchResultMapper.kt index 4d61da372..86eab1bb5 100644 --- a/data/src/main/java/com/terning/data/mapper/search/SearchResultMapper.kt +++ b/data/src/main/java/com/terning/data/mapper/search/SearchResultMapper.kt @@ -12,7 +12,7 @@ fun SearchResultResponseDto.toSearchResultList(): List { dDay = it.dDay, workingPeriod = it.workingPeriod, companyImage = it.companyImage, - scrapId = it.scrapId, + isScrapped = it.isScrapped, deadline = it.deadline, startYearMonth = it.startYearMonth, color = it.color diff --git a/domain/src/main/java/com/terning/domain/entity/search/SearchResult.kt b/domain/src/main/java/com/terning/domain/entity/search/SearchResult.kt index 057357870..3d0225003 100644 --- a/domain/src/main/java/com/terning/domain/entity/search/SearchResult.kt +++ b/domain/src/main/java/com/terning/domain/entity/search/SearchResult.kt @@ -6,8 +6,8 @@ data class SearchResult( val dDay: String, val workingPeriod: String, val companyImage: String, - val scrapId: Long?, + val isScrapped: Boolean, val deadline: String, val startYearMonth: String, val color: String?, -) \ No newline at end of file +) diff --git a/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessRoute.kt b/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessRoute.kt index 50809694c..e1d3d2eec 100644 --- a/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessRoute.kt +++ b/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessRoute.kt @@ -246,13 +246,13 @@ fun SearchProcessScreen( title = internSearchResultData[index].title, dateDeadline = internSearchResultData[index].dDay, workingPeriod = internSearchResultData[index].workingPeriod, - isScrapped = internSearchResultData[index].scrapId != null, + isScrapped = internSearchResultData[index].isScrapped, shadowWidth = 2.dp, shadowRadius = 10.dp, onScrapButtonClicked = { viewModel.updateScrapDialogVisible(true) viewModel.updateScrapped( - scrapped = internSearchResultData[index].scrapId != null + scrapped = internSearchResultData[index].isScrapped ) selectedInternIndex.intValue = index } @@ -315,7 +315,7 @@ fun SearchProcessScreen( val selectedIndex = selectedInternIndex.value if (selectedIndex != -1) { val selectedIntern = internSearchResultData[selectedIndex] - if (selectedIntern.scrapId != null) { + if (selectedIntern.isScrapped) { ScrapCancelDialog( internshipAnnouncementId = selectedIntern.internshipAnnouncementId, onDismissRequest = onDismissCancelDialog diff --git a/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessViewModel.kt b/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessViewModel.kt index b8391af88..55c995705 100644 --- a/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessViewModel.kt +++ b/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessViewModel.kt @@ -22,7 +22,6 @@ import javax.inject.Inject @HiltViewModel class SearchProcessViewModel @Inject constructor( private val searchRepository: SearchRepository, - private val scrapRepository: ScrapRepository, ) : ViewModel() { private val _state: MutableStateFlow = MutableStateFlow(SearchProcessState()) From aec2e9a946e5feff4740fb717e658367cf57b545 Mon Sep 17 00:00:00 2001 From: arinming Date: Sun, 15 Sep 2024 00:07:36 +0900 Subject: [PATCH 03/14] =?UTF-8?q?[FEAT/#250]=20SearchResultInternItem=20?= =?UTF-8?q?=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../searchprocess/SearchProcessRoute.kt | 54 +++++++++++-------- 1 file changed, 33 insertions(+), 21 deletions(-) diff --git a/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessRoute.kt b/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessRoute.kt index e1d3d2eec..a96fad1cf 100644 --- a/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessRoute.kt +++ b/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessRoute.kt @@ -51,6 +51,7 @@ import com.terning.core.extension.addFocusCleaner import com.terning.core.extension.noRippleClickable import com.terning.core.extension.toast import com.terning.domain.entity.intern.InternInfo +import com.terning.domain.entity.search.SearchResult import com.terning.feature.R import com.terning.feature.dialog.cancel.ScrapCancelDialog import com.terning.feature.dialog.detail.ScrapDialog @@ -86,7 +87,8 @@ fun SearchProcessRoute( SearchProcessScreen( modifier = modifier, - navController = navController, + navigateToIntern = { navController.navigateIntern(announcementId = it) }, + navigateToBack = { navController.navigateUp() }, currentSortBy = currentSortBy, viewModel = viewModel, onDismissCancelDialog = { @@ -106,7 +108,8 @@ fun SearchProcessRoute( fun SearchProcessScreen( currentSortBy: MutableState, modifier: Modifier = Modifier, - navController: NavHostController, + navigateToIntern: (Long) -> Unit, + navigateToBack: () -> Unit, viewModel: SearchProcessViewModel = hiltViewModel(), onDismissCancelDialog: (Boolean) -> Unit, onDismissScrapDialog: () -> Unit, @@ -146,7 +149,7 @@ fun SearchProcessScreen( if (state.showSearchResults) R.string.search_process_result_top_bar_title else R.string.search_process_top_bar_title ), - onBackButtonClick = { navController.navigateUp() }, + onBackButtonClick = navigateToBack, modifier = Modifier ) Column( @@ -235,26 +238,12 @@ fun SearchProcessScreen( verticalArrangement = Arrangement.spacedBy(12.dp) ) { items(viewModel.internSearchResultData.value.size) { index -> - InternItemWithShadow( - modifier = Modifier.noRippleClickable { - navController.navigateIntern( - announcementId = internSearchResultData[index] - .internshipAnnouncementId - ) - }, - imageUrl = internSearchResultData[index].companyImage, - title = internSearchResultData[index].title, - dateDeadline = internSearchResultData[index].dDay, - workingPeriod = internSearchResultData[index].workingPeriod, - isScrapped = internSearchResultData[index].isScrapped, - shadowWidth = 2.dp, - shadowRadius = 10.dp, + SearchResultInternItem( + navigateToIntern = navigateToIntern, + intern = internSearchResultData[index], onScrapButtonClicked = { viewModel.updateScrapDialogVisible(true) - viewModel.updateScrapped( - scrapped = internSearchResultData[index].isScrapped - ) - selectedInternIndex.intValue = index + selectedInternIndex.value = index } ) } @@ -342,6 +331,29 @@ fun SearchProcessScreen( } } +@Composable +private fun SearchResultInternItem( + intern: SearchResult, + navigateToIntern: (Long) -> Unit, + onScrapButtonClicked: (Long) -> Unit, +) { + InternItemWithShadow( + modifier = Modifier + .noRippleClickable { + navigateToIntern(intern.internshipAnnouncementId) + }, + imageUrl = intern.companyImage, + title = intern.title, + dateDeadline = intern.dDay, + workingPeriod = intern.workingPeriod, + isScrapped = intern.isScrapped, + shadowRadius = 5.dp, + shadowWidth = 1.dp, + onScrapButtonClicked = onScrapButtonClicked, + ) +} + + @Preview(showBackground = true) @Composable fun SearchProcessScreenPreview() { From 2a4bb6b27deae3109fe0327797b417332820922c Mon Sep 17 00:00:00 2001 From: arinming Date: Sun, 15 Sep 2024 00:36:11 +0900 Subject: [PATCH 04/14] =?UTF-8?q?[FEAT/#250]=20bottom=20sheet=20=EB=9D=84?= =?UTF-8?q?=EC=9A=B0=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../searchprocess/SearchProcessRoute.kt | 328 +++++++++--------- .../searchprocess/SearchProcessViewModel.kt | 54 +-- 2 files changed, 200 insertions(+), 182 deletions(-) diff --git a/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessRoute.kt b/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessRoute.kt index a96fad1cf..f7e9b9b00 100644 --- a/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessRoute.kt +++ b/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessRoute.kt @@ -17,9 +17,7 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.MutableState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableIntStateOf -import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester @@ -29,15 +27,14 @@ import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.LocalLifecycleOwner import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.flowWithLifecycle import androidx.navigation.NavHostController +import com.terning.core.designsystem.component.bottomsheet.SortingBottomSheet import com.terning.core.designsystem.component.button.SortingButton -import com.terning.core.designsystem.component.dialog.TerningBasicDialog import com.terning.core.designsystem.component.item.InternItemWithShadow import com.terning.core.designsystem.component.textfield.SearchTextField import com.terning.core.designsystem.component.topappbar.BackButtonTopAppBar @@ -45,12 +42,10 @@ import com.terning.core.designsystem.theme.CalRed import com.terning.core.designsystem.theme.Grey400 import com.terning.core.designsystem.theme.Grey500 import com.terning.core.designsystem.theme.TerningMain -import com.terning.core.designsystem.theme.TerningPointTheme import com.terning.core.designsystem.theme.TerningTheme import com.terning.core.extension.addFocusCleaner import com.terning.core.extension.noRippleClickable import com.terning.core.extension.toast -import com.terning.domain.entity.intern.InternInfo import com.terning.domain.entity.search.SearchResult import com.terning.feature.R import com.terning.feature.dialog.cancel.ScrapCancelDialog @@ -58,6 +53,7 @@ import com.terning.feature.dialog.detail.ScrapDialog import com.terning.feature.intern.navigation.navigateIntern private const val MAX_LINES = 1 +private const val SORT_BY = "deadlineSoon" @Composable fun SearchProcessRoute( @@ -68,16 +64,14 @@ fun SearchProcessRoute( val context = LocalContext.current val lifecycleOwner = LocalLifecycleOwner.current - val currentSortBy: MutableState = remember { - mutableIntStateOf(0) - } + val currentSortBy: MutableState = remember { mutableIntStateOf(0) } + val sheetState by viewModel.sheetState.collectAsStateWithLifecycle() LaunchedEffect(viewModel.sideEffect, lifecycleOwner) { - viewModel.sideEffect.flowWithLifecycle(lifecycle = lifecycleOwner.lifecycle) + viewModel.sideEffect.flowWithLifecycle(lifecycleOwner.lifecycle) .collect { sideEffect -> when (sideEffect) { is SearchProcessSideEffect.Toast -> context.toast(sideEffect.message) - is SearchProcessSideEffect.ScrapUpdate -> { sideEffect.keyword } @@ -91,16 +85,15 @@ fun SearchProcessRoute( navigateToBack = { navController.navigateUp() }, currentSortBy = currentSortBy, viewModel = viewModel, - onDismissCancelDialog = { - viewModel.updateScrapDialogVisible(false) - }, + sheetState = sheetState, + onDismissCancelDialog = { viewModel.updateScrapDialogVisible(false) }, onDismissScrapDialog = { viewModel.updateScrapDialogVisible(false) }, - onClickCancelButton = { + onScrapButtonClicked = { id -> viewModel.updateScrapDialogVisible(true) + viewModel.updateScrapped(true) + viewModel.updateSelectedInternIndex(id) }, - onClickScrapButton = { - viewModel.updateScrapDialogVisible(true) - } + onSortButtonClick = { viewModel.toggleSheetState() } ) } @@ -111,17 +104,16 @@ fun SearchProcessScreen( navigateToIntern: (Long) -> Unit, navigateToBack: () -> Unit, viewModel: SearchProcessViewModel = hiltViewModel(), + sheetState: Boolean, onDismissCancelDialog: (Boolean) -> Unit, onDismissScrapDialog: () -> Unit, - onClickCancelButton: (Long) -> Unit, - onClickScrapButton: (InternInfo) -> Unit, + onScrapButtonClicked: (Long) -> Unit, + onSortButtonClick: () -> Unit, ) { val state by viewModel.state.collectAsStateWithLifecycle() - var sheetState by remember { mutableStateOf(false) } val internSearchResultData by viewModel.internSearchResultData.collectAsStateWithLifecycle() val dialogState by viewModel.dialogState.collectAsStateWithLifecycle() - val selectedInternIndex = remember { mutableIntStateOf(-1) } - + val selectedInternIndex by viewModel.selectedInternIndex.collectAsStateWithLifecycle() val focusRequester = remember { FocusRequester() } val focusManager = LocalFocusManager.current @@ -129,7 +121,7 @@ fun SearchProcessScreen( focusRequester.requestFocus() } - LaunchedEffect(true) { + LaunchedEffect(state.text) { viewModel.getSearchList( keyword = state.text, sortBy = SORT_BY, @@ -145,13 +137,12 @@ fun SearchProcessScreen( ) { BackButtonTopAppBar( title = stringResource( - id = - if (state.showSearchResults) R.string.search_process_result_top_bar_title + id = if (state.showSearchResults) R.string.search_process_result_top_bar_title else R.string.search_process_top_bar_title ), onBackButtonClick = navigateToBack, - modifier = Modifier ) + Column( modifier = Modifier .padding(horizontal = 24.dp) @@ -170,9 +161,7 @@ fun SearchProcessScreen( SearchTextField( text = state.text, - onValueChange = { newText -> - viewModel.updateText(newText) - }, + onValueChange = { newText -> viewModel.updateText(newText) }, hint = stringResource(R.string.search_text_field_hint), leftIcon = R.drawable.ic_search_18, modifier = Modifier @@ -198,139 +187,167 @@ fun SearchProcessScreen( horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center ) { - Row( - horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.CenterVertically, - modifier = Modifier - .fillMaxWidth() - ) { - Row { - Text( - text = stringResource(id = R.string.search_process_total), - style = TerningTheme.typography.detail1, - color = Grey400, - ) - Spacer(modifier = Modifier.padding(start = 3.dp)) - Text( - text = internSearchResultData.size.toString(), - style = TerningTheme.typography.button3, - color = TerningMain, - ) - Text( - text = stringResource(id = R.string.search_process_count), - style = TerningTheme.typography.detail1, - color = Grey400, - ) - } - Row { - SortingButton( - sortBy = currentSortBy.value, - onCLick = { sheetState = true }, - ) - } - } + SearchResultsHeader( + internSearchResultData = internSearchResultData, + currentSortBy = currentSortBy, + onSortButtonClick = onSortButtonClick + ) + if (internSearchResultData.isNotEmpty()) { - LazyColumn( - contentPadding = PaddingValues( - top = 12.dp, - bottom = 20.dp, - ), - verticalArrangement = Arrangement.spacedBy(12.dp) - ) { - items(viewModel.internSearchResultData.value.size) { index -> - SearchResultInternItem( - navigateToIntern = navigateToIntern, - intern = internSearchResultData[index], - onScrapButtonClicked = { - viewModel.updateScrapDialogVisible(true) - selectedInternIndex.value = index - } - ) - } - } - } else { - Spacer( - modifier = Modifier.padding(top = 40.dp) - ) - Image( - painter = painterResource( - id = R.drawable.ic_home_empty_filtering - ), - contentDescription = stringResource( - id = R.string.search_process_no_result_icon - ) - ) - Row( - modifier = Modifier - .padding( - top = 16.dp, - bottom = 6.dp - ) - .fillMaxWidth(), - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.Center - ) { - Text( - text = state.keyword, - style = TerningTheme.typography.title4, - color = TerningMain, - maxLines = MAX_LINES, - overflow = TextOverflow.Ellipsis, - modifier = Modifier.weight(1f, false) - ) - Text( - text = stringResource(id = R.string.search_process_no_result_text_sub), - style = TerningTheme.typography.body1, - color = Grey400, - modifier = Modifier.wrapContentWidth() - ) - } - Text( - text = stringResource( - id = R.string.search_process_no_result_text_main - ), - style = TerningTheme.typography.body1, - color = Grey400, + SearchResultsList( + internSearchResultData = internSearchResultData, + navigateToIntern = navigateToIntern, + onScrapButtonClicked = onScrapButtonClicked ) + } else { + NoResultsView(state.keyword) } } } } if (dialogState.isScrapDialogVisible) { - TerningBasicDialog( - onDismissRequest = { viewModel.updateScrapDialogVisible(false) }, - content = { - val selectedIndex = selectedInternIndex.value - if (selectedIndex != -1) { - val selectedIntern = internSearchResultData[selectedIndex] - if (selectedIntern.isScrapped) { - ScrapCancelDialog( - internshipAnnouncementId = selectedIntern.internshipAnnouncementId, - onDismissRequest = onDismissCancelDialog - ) - } else { - ScrapDialog( - title = selectedIntern.title, - scrapColor = CalRed, - deadline = selectedIntern.deadline, - startYearMonth = selectedIntern.startYearMonth, - workingPeriod = selectedIntern.workingPeriod, - internshipAnnouncementId = selectedIntern.internshipAnnouncementId, - companyImage = selectedIntern.companyImage, - isScrapped = false, - onDismissRequest = onDismissScrapDialog, - onClickChangeColor = { }, - onClickNavigateButton = { } - ) - } - } - } + ScrapDialogContent( + internSearchResultData = internSearchResultData, + selectedInternIndex = selectedInternIndex, + onDismissCancelDialog = onDismissCancelDialog, + onDismissScrapDialog = onDismissScrapDialog + ) + } + + if (sheetState) { + SortingBottomSheet( + currentSortBy = currentSortBy.value, + onDismiss = { viewModel.toggleSheetState() } + ) + } + } +} + +@Composable +private fun SearchResultsHeader( + internSearchResultData: List, + currentSortBy: MutableState, + onSortButtonClick: () -> Unit, +) { + Row( + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + .fillMaxWidth() + ) { + Row { + Text( + text = stringResource(id = R.string.search_process_total), + style = TerningTheme.typography.detail1, + color = Grey400, + ) + Spacer(modifier = Modifier.padding(start = 3.dp)) + Text( + text = internSearchResultData.size.toString(), + style = TerningTheme.typography.button3, + color = TerningMain, + ) + Text( + text = stringResource(id = R.string.search_process_count), + style = TerningTheme.typography.detail1, + color = Grey400, + ) + } + Row { + SortingButton( + sortBy = currentSortBy.value, + onCLick = onSortButtonClick, ) } } } +@Composable +private fun SearchResultsList( + internSearchResultData: List, + navigateToIntern: (Long) -> Unit, + onScrapButtonClicked: (Long) -> Unit, +) { + LazyColumn( + contentPadding = PaddingValues(top = 12.dp, bottom = 20.dp), + verticalArrangement = Arrangement.spacedBy(12.dp) + ) { + items(internSearchResultData.size) { index -> + SearchResultInternItem( + intern = internSearchResultData[index], + navigateToIntern = navigateToIntern, + onScrapButtonClicked = onScrapButtonClicked, + ) + } + } +} + +@Composable +private fun NoResultsView(keyword: String) { + Spacer(modifier = Modifier.padding(top = 40.dp)) + Image( + painter = painterResource(id = R.drawable.ic_home_empty_filtering), + contentDescription = stringResource(id = R.string.search_process_no_result_icon) + ) + Row( + modifier = Modifier + .padding(top = 16.dp, bottom = 6.dp) + .fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.Center + ) { + Text( + text = keyword, + style = TerningTheme.typography.title4, + color = TerningMain, + maxLines = MAX_LINES, + overflow = TextOverflow.Ellipsis, + modifier = Modifier.weight(1f, false) + ) + Text( + text = stringResource(id = R.string.search_process_no_result_text_sub), + style = TerningTheme.typography.body1, + color = Grey400, + modifier = Modifier.wrapContentWidth() + ) + } + Text( + text = stringResource(id = R.string.search_process_no_result_text_main), + style = TerningTheme.typography.body1, + color = Grey400, + ) +} + +@Composable +private fun ScrapDialogContent( + internSearchResultData: List, + selectedInternIndex: Int, + onDismissCancelDialog: (Boolean) -> Unit, + onDismissScrapDialog: () -> Unit, +) { + val selectedIntern = internSearchResultData.getOrNull(selectedInternIndex) ?: return + + if (selectedIntern.isScrapped) { + ScrapCancelDialog( + internshipAnnouncementId = selectedIntern.internshipAnnouncementId, + onDismissRequest = onDismissCancelDialog + ) + } else { + ScrapDialog( + title = selectedIntern.title, + scrapColor = CalRed, + deadline = selectedIntern.deadline, + startYearMonth = selectedIntern.startYearMonth, + workingPeriod = selectedIntern.workingPeriod, + internshipAnnouncementId = selectedIntern.internshipAnnouncementId, + companyImage = selectedIntern.companyImage, + isScrapped = false, + onDismissRequest = onDismissScrapDialog, + ) + } +} + @Composable private fun SearchResultInternItem( intern: SearchResult, @@ -351,13 +368,4 @@ private fun SearchResultInternItem( shadowWidth = 1.dp, onScrapButtonClicked = onScrapButtonClicked, ) -} - - -@Preview(showBackground = true) -@Composable -fun SearchProcessScreenPreview() { - TerningPointTheme {} -} - -private const val SORT_BY = "deadlineSoon" \ No newline at end of file +} \ No newline at end of file diff --git a/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessViewModel.kt b/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessViewModel.kt index 55c995705..8ea721a42 100644 --- a/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessViewModel.kt +++ b/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessViewModel.kt @@ -3,7 +3,6 @@ package com.terning.feature.search.searchprocess import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.terning.domain.entity.search.SearchResult -import com.terning.domain.repository.ScrapRepository import com.terning.domain.repository.SearchRepository import com.terning.feature.R import com.terning.feature.search.searchprocess.models.SearchDialogState @@ -12,6 +11,7 @@ import com.terning.feature.search.searchprocess.models.SearchResultState import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.asStateFlow @@ -23,35 +23,39 @@ import javax.inject.Inject class SearchProcessViewModel @Inject constructor( private val searchRepository: SearchRepository, ) : ViewModel() { - private val _state: MutableStateFlow = - MutableStateFlow(SearchProcessState()) + + private val _state = MutableStateFlow(SearchProcessState()) val state: StateFlow = _state.asStateFlow() - private val _sideEffect: MutableSharedFlow = MutableSharedFlow() - val sideEffect = _sideEffect.asSharedFlow() + private val _sideEffect = MutableSharedFlow() + val sideEffect: SharedFlow = _sideEffect.asSharedFlow() - private val _searchListState: MutableStateFlow = - MutableStateFlow(SearchResultState()) + private val _searchListState = MutableStateFlow(SearchResultState()) val searchListState: StateFlow = _searchListState.asStateFlow() private val _internSearchResultData = MutableStateFlow>(emptyList()) val internSearchResultData: StateFlow> = _internSearchResultData.asStateFlow() - private val _dialogState: MutableStateFlow = - MutableStateFlow(SearchDialogState()) + private val _dialogState = MutableStateFlow(SearchDialogState()) val dialogState: StateFlow = _dialogState.asStateFlow() + private val _selectedInternIndex = MutableStateFlow(0) + val selectedInternIndex: StateFlow = _selectedInternIndex.asStateFlow() + + private val _sheetState = MutableStateFlow(false) + val sheetState: StateFlow = _sheetState.asStateFlow() + fun getSearchList( keyword: String, - sortBy: String, + sortBy: String = SORT_BY, page: Int, size: Int, ) { viewModelScope.launch { searchRepository.getSearchList(keyword, sortBy, page, size) - .onSuccess { - _internSearchResultData.value = it + .onSuccess { results -> + _internSearchResultData.value = results } .onFailure { _sideEffect.emit(SearchProcessSideEffect.Toast(R.string.server_failure)) @@ -68,26 +72,32 @@ class SearchProcessViewModel @Inject constructor( } fun updateShowSearchResults(show: Boolean) { - _state.value = _state.value.copy(showSearchResults = show) - _state.value = _state.value.copy(existSearchResults = true) + _state.value = _state.value.copy( + showSearchResults = show, + existSearchResults = true + ) } fun updateExistSearchResults(query: String) { - val exist = + val exists = _internSearchResultData.value.any { it.title.contains(query, ignoreCase = true) } - _state.value = _state.value.copy(existSearchResults = exist) + _state.value = _state.value.copy(existSearchResults = exists) } fun updateScrapDialogVisible(visible: Boolean) { - _dialogState.update { - it.copy(isScrapDialogVisible = visible) - } + _dialogState.update { it.copy(isScrapDialogVisible = visible) } } fun updateScrapped(scrapped: Boolean) { - _dialogState.update { - it.copy(scrapped = scrapped) - } + _dialogState.update { it.copy(scrapped = scrapped) } + } + + fun updateSelectedInternIndex(index: Long) { + _selectedInternIndex.value = index.toInt() + } + + fun toggleSheetState() { + _sheetState.update { !it } } companion object { From b277cd9627298d1cdd607eb52eb5cf71e45a3395 Mon Sep 17 00:00:00 2001 From: arinming Date: Sun, 15 Sep 2024 00:57:24 +0900 Subject: [PATCH 05/14] =?UTF-8?q?[FEAT/#250]=20SearchProcessViewModel=20st?= =?UTF-8?q?ate=20=EB=B3=91=ED=95=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../searchprocess/SearchProcessRoute.kt | 364 ++++++++---------- .../searchprocess/SearchProcessViewModel.kt | 33 +- .../models/SearchProcessState.kt | 9 +- 3 files changed, 184 insertions(+), 222 deletions(-) diff --git a/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessRoute.kt b/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessRoute.kt index f7e9b9b00..c1d715524 100644 --- a/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessRoute.kt +++ b/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessRoute.kt @@ -17,7 +17,9 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.MutableState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester @@ -27,14 +29,15 @@ import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.LocalLifecycleOwner import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.flowWithLifecycle import androidx.navigation.NavHostController -import com.terning.core.designsystem.component.bottomsheet.SortingBottomSheet import com.terning.core.designsystem.component.button.SortingButton +import com.terning.core.designsystem.component.dialog.TerningBasicDialog import com.terning.core.designsystem.component.item.InternItemWithShadow import com.terning.core.designsystem.component.textfield.SearchTextField import com.terning.core.designsystem.component.topappbar.BackButtonTopAppBar @@ -42,18 +45,17 @@ import com.terning.core.designsystem.theme.CalRed import com.terning.core.designsystem.theme.Grey400 import com.terning.core.designsystem.theme.Grey500 import com.terning.core.designsystem.theme.TerningMain +import com.terning.core.designsystem.theme.TerningPointTheme import com.terning.core.designsystem.theme.TerningTheme import com.terning.core.extension.addFocusCleaner import com.terning.core.extension.noRippleClickable import com.terning.core.extension.toast -import com.terning.domain.entity.search.SearchResult +import com.terning.domain.entity.intern.InternInfo import com.terning.feature.R import com.terning.feature.dialog.cancel.ScrapCancelDialog import com.terning.feature.dialog.detail.ScrapDialog import com.terning.feature.intern.navigation.navigateIntern -private const val MAX_LINES = 1 -private const val SORT_BY = "deadlineSoon" @Composable fun SearchProcessRoute( @@ -64,14 +66,16 @@ fun SearchProcessRoute( val context = LocalContext.current val lifecycleOwner = LocalLifecycleOwner.current - val currentSortBy: MutableState = remember { mutableIntStateOf(0) } - val sheetState by viewModel.sheetState.collectAsStateWithLifecycle() + val currentSortBy: MutableState = remember { + mutableIntStateOf(0) + } LaunchedEffect(viewModel.sideEffect, lifecycleOwner) { - viewModel.sideEffect.flowWithLifecycle(lifecycleOwner.lifecycle) + viewModel.sideEffect.flowWithLifecycle(lifecycle = lifecycleOwner.lifecycle) .collect { sideEffect -> when (sideEffect) { is SearchProcessSideEffect.Toast -> context.toast(sideEffect.message) + is SearchProcessSideEffect.ScrapUpdate -> { sideEffect.keyword } @@ -81,19 +85,19 @@ fun SearchProcessRoute( SearchProcessScreen( modifier = modifier, - navigateToIntern = { navController.navigateIntern(announcementId = it) }, - navigateToBack = { navController.navigateUp() }, + navController = navController, currentSortBy = currentSortBy, viewModel = viewModel, - sheetState = sheetState, - onDismissCancelDialog = { viewModel.updateScrapDialogVisible(false) }, + onDismissCancelDialog = { + viewModel.updateScrapDialogVisible(false) + }, onDismissScrapDialog = { viewModel.updateScrapDialogVisible(false) }, - onScrapButtonClicked = { id -> + onClickCancelButton = { viewModel.updateScrapDialogVisible(true) - viewModel.updateScrapped(true) - viewModel.updateSelectedInternIndex(id) }, - onSortButtonClick = { viewModel.toggleSheetState() } + onClickScrapButton = { + viewModel.updateScrapDialogVisible(true) + } ) } @@ -101,19 +105,18 @@ fun SearchProcessRoute( fun SearchProcessScreen( currentSortBy: MutableState, modifier: Modifier = Modifier, - navigateToIntern: (Long) -> Unit, - navigateToBack: () -> Unit, + navController: NavHostController, viewModel: SearchProcessViewModel = hiltViewModel(), - sheetState: Boolean, onDismissCancelDialog: (Boolean) -> Unit, onDismissScrapDialog: () -> Unit, - onScrapButtonClicked: (Long) -> Unit, - onSortButtonClick: () -> Unit, + onClickCancelButton: (Long) -> Unit, + onClickScrapButton: (InternInfo) -> Unit, ) { val state by viewModel.state.collectAsStateWithLifecycle() + var sheetState by remember { mutableStateOf(false) } val internSearchResultData by viewModel.internSearchResultData.collectAsStateWithLifecycle() - val dialogState by viewModel.dialogState.collectAsStateWithLifecycle() - val selectedInternIndex by viewModel.selectedInternIndex.collectAsStateWithLifecycle() + val selectedInternIndex = remember { mutableIntStateOf(-1) } + val focusRequester = remember { FocusRequester() } val focusManager = LocalFocusManager.current @@ -121,7 +124,7 @@ fun SearchProcessScreen( focusRequester.requestFocus() } - LaunchedEffect(state.text) { + LaunchedEffect(true) { viewModel.getSearchList( keyword = state.text, sortBy = SORT_BY, @@ -137,12 +140,13 @@ fun SearchProcessScreen( ) { BackButtonTopAppBar( title = stringResource( - id = if (state.showSearchResults) R.string.search_process_result_top_bar_title + id = + if (state.showSearchResults) R.string.search_process_result_top_bar_title else R.string.search_process_top_bar_title ), - onBackButtonClick = navigateToBack, + onBackButtonClick = { navController.navigateUp() }, + modifier = Modifier ) - Column( modifier = Modifier .padding(horizontal = 24.dp) @@ -161,7 +165,9 @@ fun SearchProcessScreen( SearchTextField( text = state.text, - onValueChange = { newText -> viewModel.updateText(newText) }, + onValueChange = { newText -> + viewModel.updateText(newText) + }, hint = stringResource(R.string.search_text_field_hint), leftIcon = R.drawable.ic_search_18, modifier = Modifier @@ -187,185 +193,151 @@ fun SearchProcessScreen( horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center ) { - SearchResultsHeader( - internSearchResultData = internSearchResultData, - currentSortBy = currentSortBy, - onSortButtonClick = onSortButtonClick - ) - + Row( + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + .fillMaxWidth() + ) { + Row { + Text( + text = stringResource(id = R.string.search_process_total), + style = TerningTheme.typography.detail1, + color = Grey400, + ) + Spacer(modifier = Modifier.padding(start = 3.dp)) + Text( + text = internSearchResultData.size.toString(), + style = TerningTheme.typography.button3, + color = TerningMain, + ) + Text( + text = stringResource(id = R.string.search_process_count), + style = TerningTheme.typography.detail1, + color = Grey400, + ) + } + Row { + SortingButton( + sortBy = currentSortBy.value, + onCLick = { sheetState = true }, + ) + } + } if (internSearchResultData.isNotEmpty()) { - SearchResultsList( - internSearchResultData = internSearchResultData, - navigateToIntern = navigateToIntern, - onScrapButtonClicked = onScrapButtonClicked - ) + LazyColumn( + contentPadding = PaddingValues( + top = 12.dp, + bottom = 20.dp, + ), + verticalArrangement = Arrangement.spacedBy(12.dp) + ) { + items(viewModel.internSearchResultData.value.size) { index -> + InternItemWithShadow( + modifier = Modifier.noRippleClickable { + navController.navigateIntern( + announcementId = internSearchResultData[index] + .internshipAnnouncementId + ) + }, + imageUrl = internSearchResultData[index].companyImage, + title = internSearchResultData[index].title, + dateDeadline = internSearchResultData[index].dDay, + workingPeriod = internSearchResultData[index].workingPeriod, + isScrapped = internSearchResultData[index].isScrapped, + shadowWidth = 2.dp, + shadowRadius = 10.dp, + onScrapButtonClicked = { + viewModel.updateScrapDialogVisible(true) + viewModel.updateScrapped( + scrapped = internSearchResultData[index].isScrapped + ) + selectedInternIndex.intValue = index + } + ) + } + } } else { - NoResultsView(state.keyword) + Spacer( + modifier = Modifier.padding(top = 40.dp) + ) + Image( + painter = painterResource( + id = R.drawable.ic_home_empty_filtering + ), + contentDescription = stringResource( + id = R.string.search_process_no_result_icon + ) + ) + Row( + modifier = Modifier + .padding( + top = 16.dp, + bottom = 6.dp + ) + .fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.Center + ) { + Text( + text = state.keyword, + style = TerningTheme.typography.title4, + color = TerningMain, + maxLines = MAX_LINES, + overflow = TextOverflow.Ellipsis, + modifier = Modifier.weight(1f, false) + ) + Text( + text = stringResource(id = R.string.search_process_no_result_text_sub), + style = TerningTheme.typography.body1, + color = Grey400, + modifier = Modifier.wrapContentWidth() + ) + } + Text( + text = stringResource( + id = R.string.search_process_no_result_text_main + ), + style = TerningTheme.typography.body1, + color = Grey400, + ) } } } } - if (dialogState.isScrapDialogVisible) { - ScrapDialogContent( - internSearchResultData = internSearchResultData, - selectedInternIndex = selectedInternIndex, - onDismissCancelDialog = onDismissCancelDialog, - onDismissScrapDialog = onDismissScrapDialog - ) - } - - if (sheetState) { - SortingBottomSheet( - currentSortBy = currentSortBy.value, - onDismiss = { viewModel.toggleSheetState() } - ) - } - } -} - -@Composable -private fun SearchResultsHeader( - internSearchResultData: List, - currentSortBy: MutableState, - onSortButtonClick: () -> Unit, -) { - Row( - horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.CenterVertically, - modifier = Modifier - .fillMaxWidth() - ) { - Row { - Text( - text = stringResource(id = R.string.search_process_total), - style = TerningTheme.typography.detail1, - color = Grey400, - ) - Spacer(modifier = Modifier.padding(start = 3.dp)) - Text( - text = internSearchResultData.size.toString(), - style = TerningTheme.typography.button3, - color = TerningMain, - ) - Text( - text = stringResource(id = R.string.search_process_count), - style = TerningTheme.typography.detail1, - color = Grey400, - ) - } - Row { - SortingButton( - sortBy = currentSortBy.value, - onCLick = onSortButtonClick, - ) - } - } -} - -@Composable -private fun SearchResultsList( - internSearchResultData: List, - navigateToIntern: (Long) -> Unit, - onScrapButtonClicked: (Long) -> Unit, -) { - LazyColumn( - contentPadding = PaddingValues(top = 12.dp, bottom = 20.dp), - verticalArrangement = Arrangement.spacedBy(12.dp) - ) { - items(internSearchResultData.size) { index -> - SearchResultInternItem( - intern = internSearchResultData[index], - navigateToIntern = navigateToIntern, - onScrapButtonClicked = onScrapButtonClicked, + if (state.isScrapDialogVisible) { + TerningBasicDialog( + onDismissRequest = { viewModel.updateScrapDialogVisible(false) }, + content = { + val selectedIndex = selectedInternIndex.value + if (selectedIndex != -1) { + val selectedIntern = internSearchResultData[selectedIndex] + if (selectedIntern.isScrapped) { + ScrapCancelDialog( + internshipAnnouncementId = selectedIntern.internshipAnnouncementId, + onDismissRequest = onDismissCancelDialog + ) + } else { + ScrapDialog( + title = selectedIntern.title, + scrapColor = CalRed, + deadline = selectedIntern.deadline, + startYearMonth = selectedIntern.startYearMonth, + workingPeriod = selectedIntern.workingPeriod, + internshipAnnouncementId = selectedIntern.internshipAnnouncementId, + companyImage = selectedIntern.companyImage, + isScrapped = false, + onDismissRequest = onDismissScrapDialog, + ) + } + } + } ) } } } -@Composable -private fun NoResultsView(keyword: String) { - Spacer(modifier = Modifier.padding(top = 40.dp)) - Image( - painter = painterResource(id = R.drawable.ic_home_empty_filtering), - contentDescription = stringResource(id = R.string.search_process_no_result_icon) - ) - Row( - modifier = Modifier - .padding(top = 16.dp, bottom = 6.dp) - .fillMaxWidth(), - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.Center - ) { - Text( - text = keyword, - style = TerningTheme.typography.title4, - color = TerningMain, - maxLines = MAX_LINES, - overflow = TextOverflow.Ellipsis, - modifier = Modifier.weight(1f, false) - ) - Text( - text = stringResource(id = R.string.search_process_no_result_text_sub), - style = TerningTheme.typography.body1, - color = Grey400, - modifier = Modifier.wrapContentWidth() - ) - } - Text( - text = stringResource(id = R.string.search_process_no_result_text_main), - style = TerningTheme.typography.body1, - color = Grey400, - ) -} - -@Composable -private fun ScrapDialogContent( - internSearchResultData: List, - selectedInternIndex: Int, - onDismissCancelDialog: (Boolean) -> Unit, - onDismissScrapDialog: () -> Unit, -) { - val selectedIntern = internSearchResultData.getOrNull(selectedInternIndex) ?: return - - if (selectedIntern.isScrapped) { - ScrapCancelDialog( - internshipAnnouncementId = selectedIntern.internshipAnnouncementId, - onDismissRequest = onDismissCancelDialog - ) - } else { - ScrapDialog( - title = selectedIntern.title, - scrapColor = CalRed, - deadline = selectedIntern.deadline, - startYearMonth = selectedIntern.startYearMonth, - workingPeriod = selectedIntern.workingPeriod, - internshipAnnouncementId = selectedIntern.internshipAnnouncementId, - companyImage = selectedIntern.companyImage, - isScrapped = false, - onDismissRequest = onDismissScrapDialog, - ) - } -} -@Composable -private fun SearchResultInternItem( - intern: SearchResult, - navigateToIntern: (Long) -> Unit, - onScrapButtonClicked: (Long) -> Unit, -) { - InternItemWithShadow( - modifier = Modifier - .noRippleClickable { - navigateToIntern(intern.internshipAnnouncementId) - }, - imageUrl = intern.companyImage, - title = intern.title, - dateDeadline = intern.dDay, - workingPeriod = intern.workingPeriod, - isScrapped = intern.isScrapped, - shadowRadius = 5.dp, - shadowWidth = 1.dp, - onScrapButtonClicked = onScrapButtonClicked, - ) -} \ No newline at end of file +private const val MAX_LINES = 1 +private const val SORT_BY = "deadlineSoon" \ No newline at end of file diff --git a/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessViewModel.kt b/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessViewModel.kt index 8ea721a42..249d60b05 100644 --- a/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessViewModel.kt +++ b/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessViewModel.kt @@ -5,9 +5,7 @@ import androidx.lifecycle.viewModelScope import com.terning.domain.entity.search.SearchResult import com.terning.domain.repository.SearchRepository import com.terning.feature.R -import com.terning.feature.search.searchprocess.models.SearchDialogState import com.terning.feature.search.searchprocess.models.SearchProcessState -import com.terning.feature.search.searchprocess.models.SearchResultState import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow @@ -30,22 +28,10 @@ class SearchProcessViewModel @Inject constructor( private val _sideEffect = MutableSharedFlow() val sideEffect: SharedFlow = _sideEffect.asSharedFlow() - private val _searchListState = MutableStateFlow(SearchResultState()) - val searchListState: StateFlow = _searchListState.asStateFlow() - private val _internSearchResultData = MutableStateFlow>(emptyList()) val internSearchResultData: StateFlow> = _internSearchResultData.asStateFlow() - private val _dialogState = MutableStateFlow(SearchDialogState()) - val dialogState: StateFlow = _dialogState.asStateFlow() - - private val _selectedInternIndex = MutableStateFlow(0) - val selectedInternIndex: StateFlow = _selectedInternIndex.asStateFlow() - - private val _sheetState = MutableStateFlow(false) - val sheetState: StateFlow = _sheetState.asStateFlow() - fun getSearchList( keyword: String, sortBy: String = SORT_BY, @@ -64,40 +50,37 @@ class SearchProcessViewModel @Inject constructor( } fun updateText(newText: String) { - _state.value = _state.value.copy(text = newText) + _state.update { it.copy(text = newText) } } fun updateQuery(query: String) { - _state.value = _state.value.copy(keyword = query) + _state.update { it.copy(keyword = query) } } fun updateShowSearchResults(show: Boolean) { - _state.value = _state.value.copy( - showSearchResults = show, - existSearchResults = true - ) + _state.update { it.copy(showSearchResults = show, existSearchResults = true) } } fun updateExistSearchResults(query: String) { val exists = _internSearchResultData.value.any { it.title.contains(query, ignoreCase = true) } - _state.value = _state.value.copy(existSearchResults = exists) + _state.update { it.copy(existSearchResults = exists) } } fun updateScrapDialogVisible(visible: Boolean) { - _dialogState.update { it.copy(isScrapDialogVisible = visible) } + _state.update { it.copy(isScrapDialogVisible = visible) } } fun updateScrapped(scrapped: Boolean) { - _dialogState.update { it.copy(scrapped = scrapped) } + _state.update { it.copy(scrapped = scrapped) } } fun updateSelectedInternIndex(index: Long) { - _selectedInternIndex.value = index.toInt() + _state.update { it.copy(selectedInternIndex = index.toInt()) } } fun toggleSheetState() { - _sheetState.update { !it } + _state.update { it.copy(sheetState = !it.sheetState) } } companion object { diff --git a/feature/src/main/java/com/terning/feature/search/searchprocess/models/SearchProcessState.kt b/feature/src/main/java/com/terning/feature/search/searchprocess/models/SearchProcessState.kt index ea1f030dd..7012d62f6 100644 --- a/feature/src/main/java/com/terning/feature/search/searchprocess/models/SearchProcessState.kt +++ b/feature/src/main/java/com/terning/feature/search/searchprocess/models/SearchProcessState.kt @@ -1,9 +1,16 @@ package com.terning.feature.search.searchprocess.models +import com.terning.core.state.UiState +import com.terning.domain.entity.search.SearchResult data class SearchProcessState( + val loadState: UiState = UiState.Loading, val text: String = "", val keyword: String = "", val showSearchResults: Boolean = false, val existSearchResults: Boolean = false, -) \ No newline at end of file + val isScrapDialogVisible: Boolean = false, + val scrapped: Boolean = false, + val selectedInternIndex: Int = 0, + val sheetState: Boolean = false, +) From 91ba193712982cd0d0126525d7dffbef054db20e Mon Sep 17 00:00:00 2001 From: arinming Date: Sun, 15 Sep 2024 02:01:43 +0900 Subject: [PATCH 06/14] =?UTF-8?q?[FEAT/#250]=20=EA=B2=80=EC=83=89=20?= =?UTF-8?q?=EA=B2=B0=EA=B3=BC=20=ED=99=94=EB=A9=B4=20Scrap=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../searchprocess/SearchProcessRoute.kt | 226 +++++++++++------- .../searchprocess/SearchProcessViewModel.kt | 36 ++- .../models/SearchProcessState.kt | 14 ++ 3 files changed, 175 insertions(+), 101 deletions(-) diff --git a/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessRoute.kt b/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessRoute.kt index c1d715524..408262eaa 100644 --- a/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessRoute.kt +++ b/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessRoute.kt @@ -17,9 +17,7 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.MutableState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableIntStateOf -import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester @@ -29,15 +27,14 @@ import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.LocalLifecycleOwner import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.flowWithLifecycle import androidx.navigation.NavHostController +import com.terning.core.designsystem.component.bottomsheet.SortingBottomSheet import com.terning.core.designsystem.component.button.SortingButton -import com.terning.core.designsystem.component.dialog.TerningBasicDialog import com.terning.core.designsystem.component.item.InternItemWithShadow import com.terning.core.designsystem.component.textfield.SearchTextField import com.terning.core.designsystem.component.topappbar.BackButtonTopAppBar @@ -45,16 +42,16 @@ import com.terning.core.designsystem.theme.CalRed import com.terning.core.designsystem.theme.Grey400 import com.terning.core.designsystem.theme.Grey500 import com.terning.core.designsystem.theme.TerningMain -import com.terning.core.designsystem.theme.TerningPointTheme import com.terning.core.designsystem.theme.TerningTheme import com.terning.core.extension.addFocusCleaner import com.terning.core.extension.noRippleClickable import com.terning.core.extension.toast -import com.terning.domain.entity.intern.InternInfo +import com.terning.domain.entity.search.SearchResult import com.terning.feature.R import com.terning.feature.dialog.cancel.ScrapCancelDialog import com.terning.feature.dialog.detail.ScrapDialog import com.terning.feature.intern.navigation.navigateIntern +import com.terning.feature.search.searchprocess.models.SearchProcessState @Composable @@ -63,6 +60,9 @@ fun SearchProcessRoute( navController: NavHostController, viewModel: SearchProcessViewModel = hiltViewModel(), ) { + val state by viewModel.state.collectAsStateWithLifecycle() + val internSearchResultData by viewModel.internSearchResultData.collectAsStateWithLifecycle() + val context = LocalContext.current val lifecycleOwner = LocalLifecycleOwner.current @@ -70,6 +70,15 @@ fun SearchProcessRoute( mutableIntStateOf(0) } + LaunchedEffect(true) { + viewModel.getSearchList( + keyword = state.text, + sortBy = SORT_BY, + page = 0, + size = 10 + ) + } + LaunchedEffect(viewModel.sideEffect, lifecycleOwner) { viewModel.sideEffect.flowWithLifecycle(lifecycle = lifecycleOwner.lifecycle) .collect { sideEffect -> @@ -85,18 +94,59 @@ fun SearchProcessRoute( SearchProcessScreen( modifier = modifier, - navController = navController, + navigateToIntern = { navController.navigateIntern(it) }, + navigateToBack = { navController.navigateUp() }, currentSortBy = currentSortBy, - viewModel = viewModel, + state = state, + internSearchResultData = internSearchResultData, + updateText = { + viewModel.updateText(it) + }, + onSearchAction = { + viewModel.getSearchList( + keyword = state.text, + sortBy = SORT_BY, + page = 0, + size = 10, + ) + viewModel.updateQuery(state.text) + viewModel.updateShowSearchResults(true) + viewModel.updateExistSearchResults(state.text) + }, + onSortButtonClick = { + viewModel.toggleSheetState() + }, onDismissCancelDialog = { + viewModel.getSearchList( + keyword = state.keyword, + sortBy = state.sortBy, + page = state.page, + size = state.size + ) viewModel.updateScrapDialogVisible(false) }, - onDismissScrapDialog = { viewModel.updateScrapDialogVisible(false) }, - onClickCancelButton = { - viewModel.updateScrapDialogVisible(true) + onDismissScrapDialog = { + viewModel.getSearchList( + keyword = state.keyword, + sortBy = state.sortBy, + page = state.page, + size = state.size + ) + viewModel.updateScrapDialogVisible(false) }, - onClickScrapButton = { + onScrapButtonClicked = { viewModel.updateScrapDialogVisible(true) + viewModel.updateSearchResult( + internshipId = it.internshipAnnouncementId, + title = it.title, + dDay = it.dDay, + deadline = it.deadline, + startYearMonth = it.startYearMonth, + workingPeriod = it.workingPeriod, + companyImage = it.companyImage, + isScrapped = it.isScrapped, + color = it.color + ) } ) } @@ -105,18 +155,17 @@ fun SearchProcessRoute( fun SearchProcessScreen( currentSortBy: MutableState, modifier: Modifier = Modifier, - navController: NavHostController, - viewModel: SearchProcessViewModel = hiltViewModel(), + navigateToIntern: (Long) -> Unit, + navigateToBack: () -> Unit, + state: SearchProcessState = SearchProcessState(), + internSearchResultData: List = emptyList(), + updateText: (String) -> Unit = {}, + onSearchAction: () -> Unit = {}, + onSortButtonClick: () -> Unit = {}, onDismissCancelDialog: (Boolean) -> Unit, onDismissScrapDialog: () -> Unit, - onClickCancelButton: (Long) -> Unit, - onClickScrapButton: (InternInfo) -> Unit, + onScrapButtonClicked: (SearchResult) -> Unit, ) { - val state by viewModel.state.collectAsStateWithLifecycle() - var sheetState by remember { mutableStateOf(false) } - val internSearchResultData by viewModel.internSearchResultData.collectAsStateWithLifecycle() - val selectedInternIndex = remember { mutableIntStateOf(-1) } - val focusRequester = remember { FocusRequester() } val focusManager = LocalFocusManager.current @@ -124,15 +173,6 @@ fun SearchProcessScreen( focusRequester.requestFocus() } - LaunchedEffect(true) { - viewModel.getSearchList( - keyword = state.text, - sortBy = SORT_BY, - page = 0, - size = 10 - ) - } - Column( modifier = modifier .fillMaxSize() @@ -144,7 +184,7 @@ fun SearchProcessScreen( if (state.showSearchResults) R.string.search_process_result_top_bar_title else R.string.search_process_top_bar_title ), - onBackButtonClick = { navController.navigateUp() }, + onBackButtonClick = navigateToBack, modifier = Modifier ) Column( @@ -166,26 +206,15 @@ fun SearchProcessScreen( SearchTextField( text = state.text, onValueChange = { newText -> - viewModel.updateText(newText) + updateText(newText) }, hint = stringResource(R.string.search_text_field_hint), leftIcon = R.drawable.ic_search_18, modifier = Modifier .focusRequester(focusRequester) .addFocusCleaner(focusManager), - onSearchAction = { - viewModel.getSearchList( - keyword = state.text, - sortBy = SORT_BY, - page = 0, - size = 10 - ) - viewModel.updateQuery(state.text) - viewModel.updateShowSearchResults(true) - viewModel.updateExistSearchResults(state.text) - } + onSearchAction = onSearchAction ) - if (state.showSearchResults) { Column( modifier = Modifier @@ -193,6 +222,8 @@ fun SearchProcessScreen( horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center ) { + + Row( horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically, @@ -220,11 +251,12 @@ fun SearchProcessScreen( Row { SortingButton( sortBy = currentSortBy.value, - onCLick = { sheetState = true }, + onCLick = onSortButtonClick, ) } } - if (internSearchResultData.isNotEmpty()) { + + if (state.existSearchResults) { LazyColumn( contentPadding = PaddingValues( top = 12.dp, @@ -232,27 +264,12 @@ fun SearchProcessScreen( ), verticalArrangement = Arrangement.spacedBy(12.dp) ) { - items(viewModel.internSearchResultData.value.size) { index -> - InternItemWithShadow( - modifier = Modifier.noRippleClickable { - navController.navigateIntern( - announcementId = internSearchResultData[index] - .internshipAnnouncementId - ) - }, - imageUrl = internSearchResultData[index].companyImage, - title = internSearchResultData[index].title, - dateDeadline = internSearchResultData[index].dDay, - workingPeriod = internSearchResultData[index].workingPeriod, - isScrapped = internSearchResultData[index].isScrapped, - shadowWidth = 2.dp, - shadowRadius = 10.dp, + items(internSearchResultData.size) { index -> + SearchResultInternItem( + intern = internSearchResultData[index], + navigateToIntern = navigateToIntern, onScrapButtonClicked = { - viewModel.updateScrapDialogVisible(true) - viewModel.updateScrapped( - scrapped = internSearchResultData[index].isScrapped - ) - selectedInternIndex.intValue = index + onScrapButtonClicked(internSearchResultData[index]) } ) } @@ -306,38 +323,61 @@ fun SearchProcessScreen( } } - if (state.isScrapDialogVisible) { - TerningBasicDialog( - onDismissRequest = { viewModel.updateScrapDialogVisible(false) }, - content = { - val selectedIndex = selectedInternIndex.value - if (selectedIndex != -1) { - val selectedIntern = internSearchResultData[selectedIndex] - if (selectedIntern.isScrapped) { - ScrapCancelDialog( - internshipAnnouncementId = selectedIntern.internshipAnnouncementId, - onDismissRequest = onDismissCancelDialog - ) - } else { - ScrapDialog( - title = selectedIntern.title, - scrapColor = CalRed, - deadline = selectedIntern.deadline, - startYearMonth = selectedIntern.startYearMonth, - workingPeriod = selectedIntern.workingPeriod, - internshipAnnouncementId = selectedIntern.internshipAnnouncementId, - companyImage = selectedIntern.companyImage, - isScrapped = false, - onDismissRequest = onDismissScrapDialog, - ) - } - } - } + if (state.sheetState) { + SortingBottomSheet( + currentSortBy = currentSortBy.value, + onDismiss = onSortButtonClick ) } + + if (state.isScrapDialogVisible) { + val searchResult = state.searchResult + if (searchResult.isScrapped) { + ScrapCancelDialog( + internshipAnnouncementId = searchResult.internshipAnnouncementId, + onDismissRequest = onDismissCancelDialog + ) + } else { + ScrapDialog( + title = searchResult.title, + scrapColor = CalRed, + deadline = searchResult.deadline, + startYearMonth = searchResult.startYearMonth, + workingPeriod = searchResult.workingPeriod, + internshipAnnouncementId = searchResult.internshipAnnouncementId, + companyImage = searchResult.companyImage, + isScrapped = false, + onDismissRequest = onDismissScrapDialog, + ) + } + } } } +@Composable +private fun SearchResultInternItem( + intern: SearchResult, + navigateToIntern: (Long) -> Unit, + onScrapButtonClicked: (Long) -> Unit, +) { + InternItemWithShadow( + modifier = Modifier + .noRippleClickable { + navigateToIntern(intern.internshipAnnouncementId) + }, + imageUrl = intern.companyImage, + title = intern.title, + dateDeadline = intern.dDay, + workingPeriod = intern.workingPeriod, + isScrapped = intern.isScrapped, + shadowRadius = 5.dp, + shadowWidth = 1.dp, + onScrapButtonClicked = { + onScrapButtonClicked(intern.internshipAnnouncementId) + }, + ) +} + private const val MAX_LINES = 1 private const val SORT_BY = "deadlineSoon" \ No newline at end of file diff --git a/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessViewModel.kt b/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessViewModel.kt index 249d60b05..00ae4acd6 100644 --- a/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessViewModel.kt +++ b/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessViewModel.kt @@ -49,6 +49,34 @@ class SearchProcessViewModel @Inject constructor( } } + fun updateSearchResult( + internshipId: Long, + title: String, + dDay: String, + workingPeriod: String, + companyImage: String, + isScrapped: Boolean, + deadline: String, + startYearMonth: String, + color: String? + ) { + _state.update { + it.copy( + searchResult = SearchResult( + internshipAnnouncementId = internshipId, + title = title, + dDay = dDay, + workingPeriod = workingPeriod, + companyImage = companyImage, + isScrapped = isScrapped, + deadline = deadline, + startYearMonth = startYearMonth, + color = color ?: "" + ) + ) + } + } + fun updateText(newText: String) { _state.update { it.copy(text = newText) } } @@ -71,14 +99,6 @@ class SearchProcessViewModel @Inject constructor( _state.update { it.copy(isScrapDialogVisible = visible) } } - fun updateScrapped(scrapped: Boolean) { - _state.update { it.copy(scrapped = scrapped) } - } - - fun updateSelectedInternIndex(index: Long) { - _state.update { it.copy(selectedInternIndex = index.toInt()) } - } - fun toggleSheetState() { _state.update { it.copy(sheetState = !it.sheetState) } } diff --git a/feature/src/main/java/com/terning/feature/search/searchprocess/models/SearchProcessState.kt b/feature/src/main/java/com/terning/feature/search/searchprocess/models/SearchProcessState.kt index 7012d62f6..e9cbbe947 100644 --- a/feature/src/main/java/com/terning/feature/search/searchprocess/models/SearchProcessState.kt +++ b/feature/src/main/java/com/terning/feature/search/searchprocess/models/SearchProcessState.kt @@ -7,10 +7,24 @@ data class SearchProcessState( val loadState: UiState = UiState.Loading, val text: String = "", val keyword: String = "", + val sortBy: String = "", + val page: Int = 0, + val size: Int = 10, val showSearchResults: Boolean = false, val existSearchResults: Boolean = false, val isScrapDialogVisible: Boolean = false, val scrapped: Boolean = false, val selectedInternIndex: Int = 0, val sheetState: Boolean = false, + val searchResult: SearchResult = SearchResult( + internshipAnnouncementId = 0, + title = "", + companyImage = "", + dDay = "", + workingPeriod = "", + isScrapped = false, + deadline = "", + startYearMonth = "", + color = "", + ), ) From a2c5a02ab9dbfb669bbd61d33fd00fe703fd5cae Mon Sep 17 00:00:00 2001 From: arinming Date: Sun, 15 Sep 2024 02:42:57 +0900 Subject: [PATCH 07/14] =?UTF-8?q?[FEAT/#250]=20=EA=B2=80=EC=83=89=20?= =?UTF-8?q?=EA=B2=B0=EA=B3=BC=20=ED=99=94=EB=A9=B4=20Sorting=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bottomsheet/SortingBottomSheet.kt | 8 ++--- .../searchprocess/SearchProcessRoute.kt | 36 ++++++++++--------- .../searchprocess/SearchProcessViewModel.kt | 25 ++++++++----- .../models/SearchProcessState.kt | 5 ++- 4 files changed, 43 insertions(+), 31 deletions(-) diff --git a/core/src/main/java/com/terning/core/designsystem/component/bottomsheet/SortingBottomSheet.kt b/core/src/main/java/com/terning/core/designsystem/component/bottomsheet/SortingBottomSheet.kt index 806fefee3..abdfb0b9e 100644 --- a/core/src/main/java/com/terning/core/designsystem/component/bottomsheet/SortingBottomSheet.kt +++ b/core/src/main/java/com/terning/core/designsystem/component/bottomsheet/SortingBottomSheet.kt @@ -10,11 +10,8 @@ import androidx.compose.material3.Text import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableState -import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope -import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign @@ -36,10 +33,10 @@ fun SortingBottomSheet( currentSortBy: Int, modifier: Modifier = Modifier, newSortBy: MutableState = mutableStateOf(currentSortBy), + onSortChange: (Int) -> Unit = {}, ) { val scope = rememberCoroutineScope() val sheetState = rememberModalBottomSheetState() - var currentSortBy by remember { mutableStateOf(currentSortBy) } TerningBasicBottomSheet( content = { @@ -75,6 +72,7 @@ fun SortingBottomSheet( .padding(vertical = 12.dp) .noRippleClickable { newSortBy.value = sortIndex + onSortChange(sortIndex) scope .launch { sheetState.hide() } .invokeOnCompletion { @@ -87,7 +85,7 @@ fun SortingBottomSheet( } } }, - onDismissRequest = { onDismiss() }, + onDismissRequest = onDismiss, sheetState = sheetState ) } diff --git a/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessRoute.kt b/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessRoute.kt index 408262eaa..a4f000a03 100644 --- a/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessRoute.kt +++ b/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessRoute.kt @@ -14,7 +14,6 @@ import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.MutableState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.remember @@ -66,14 +65,10 @@ fun SearchProcessRoute( val context = LocalContext.current val lifecycleOwner = LocalLifecycleOwner.current - val currentSortBy: MutableState = remember { - mutableIntStateOf(0) - } - LaunchedEffect(true) { viewModel.getSearchList( keyword = state.text, - sortBy = SORT_BY, + sortBy = state.currentSortBy, page = 0, size = 10 ) @@ -96,7 +91,6 @@ fun SearchProcessRoute( modifier = modifier, navigateToIntern = { navController.navigateIntern(it) }, navigateToBack = { navController.navigateUp() }, - currentSortBy = currentSortBy, state = state, internSearchResultData = internSearchResultData, updateText = { @@ -105,7 +99,7 @@ fun SearchProcessRoute( onSearchAction = { viewModel.getSearchList( keyword = state.text, - sortBy = SORT_BY, + sortBy = state.currentSortBy, page = 0, size = 10, ) @@ -114,12 +108,12 @@ fun SearchProcessRoute( viewModel.updateExistSearchResults(state.text) }, onSortButtonClick = { - viewModel.toggleSheetState() + viewModel.updateSheetVisible(true) }, onDismissCancelDialog = { viewModel.getSearchList( keyword = state.keyword, - sortBy = state.sortBy, + sortBy = state.sortBy.ordinal, page = state.page, size = state.size ) @@ -128,12 +122,15 @@ fun SearchProcessRoute( onDismissScrapDialog = { viewModel.getSearchList( keyword = state.keyword, - sortBy = state.sortBy, + sortBy = state.sortBy.ordinal, page = state.page, size = state.size ) viewModel.updateScrapDialogVisible(false) }, + onDismissSheet = { + viewModel.updateSheetVisible(false) + }, onScrapButtonClicked = { viewModel.updateScrapDialogVisible(true) viewModel.updateSearchResult( @@ -147,13 +144,15 @@ fun SearchProcessRoute( isScrapped = it.isScrapped, color = it.color ) + }, + onSortChange = { + viewModel.updateSortBy(it) } ) } @Composable fun SearchProcessScreen( - currentSortBy: MutableState, modifier: Modifier = Modifier, navigateToIntern: (Long) -> Unit, navigateToBack: () -> Unit, @@ -164,7 +163,9 @@ fun SearchProcessScreen( onSortButtonClick: () -> Unit = {}, onDismissCancelDialog: (Boolean) -> Unit, onDismissScrapDialog: () -> Unit, + onDismissSheet: () -> Unit = {}, onScrapButtonClicked: (SearchResult) -> Unit, + onSortChange: (Int) -> Unit = {}, ) { val focusRequester = remember { FocusRequester() } val focusManager = LocalFocusManager.current @@ -250,7 +251,7 @@ fun SearchProcessScreen( } Row { SortingButton( - sortBy = currentSortBy.value, + sortBy = state.currentSortBy, onCLick = onSortButtonClick, ) } @@ -325,8 +326,10 @@ fun SearchProcessScreen( if (state.sheetState) { SortingBottomSheet( - currentSortBy = currentSortBy.value, - onDismiss = onSortButtonClick + currentSortBy = state.currentSortBy, + onDismiss = onDismissSheet, + newSortBy = mutableIntStateOf(state.currentSortBy), + onSortChange = onSortChange ) } @@ -379,5 +382,4 @@ private fun SearchResultInternItem( ) } -private const val MAX_LINES = 1 -private const val SORT_BY = "deadlineSoon" \ No newline at end of file +private const val MAX_LINES = 1 \ No newline at end of file diff --git a/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessViewModel.kt b/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessViewModel.kt index 00ae4acd6..08280467d 100644 --- a/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessViewModel.kt +++ b/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessViewModel.kt @@ -2,6 +2,7 @@ package com.terning.feature.search.searchprocess import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.terning.core.type.SortBy import com.terning.domain.entity.search.SearchResult import com.terning.domain.repository.SearchRepository import com.terning.feature.R @@ -31,15 +32,17 @@ class SearchProcessViewModel @Inject constructor( private val _internSearchResultData = MutableStateFlow>(emptyList()) val internSearchResultData: StateFlow> = _internSearchResultData.asStateFlow() - fun getSearchList( keyword: String, - sortBy: String = SORT_BY, + sortBy: Int, page: Int, size: Int, ) { + if (sortBy < 0 || sortBy >= SortBy.entries.size) { + return + } viewModelScope.launch { - searchRepository.getSearchList(keyword, sortBy, page, size) + searchRepository.getSearchList(keyword, SortBy.entries[sortBy].type, page, size) .onSuccess { results -> _internSearchResultData.value = results } @@ -58,7 +61,7 @@ class SearchProcessViewModel @Inject constructor( isScrapped: Boolean, deadline: String, startYearMonth: String, - color: String? + color: String?, ) { _state.update { it.copy( @@ -99,11 +102,17 @@ class SearchProcessViewModel @Inject constructor( _state.update { it.copy(isScrapDialogVisible = visible) } } - fun toggleSheetState() { - _state.update { it.copy(sheetState = !it.sheetState) } + fun updateSheetVisible(visible: Boolean) { + _state.update { it.copy(sheetState = visible) } } - companion object { - private const val SORT_BY = "deadlineSoon" + fun updateSortBy(newSortBy: Int) { + _state.value = _state.value.copy(currentSortBy = newSortBy) + getSearchList( + keyword = _state.value.keyword, + sortBy = newSortBy, + page = 0, + size = 10 + ) } } diff --git a/feature/src/main/java/com/terning/feature/search/searchprocess/models/SearchProcessState.kt b/feature/src/main/java/com/terning/feature/search/searchprocess/models/SearchProcessState.kt index e9cbbe947..394edd35f 100644 --- a/feature/src/main/java/com/terning/feature/search/searchprocess/models/SearchProcessState.kt +++ b/feature/src/main/java/com/terning/feature/search/searchprocess/models/SearchProcessState.kt @@ -1,13 +1,15 @@ package com.terning.feature.search.searchprocess.models import com.terning.core.state.UiState +import com.terning.core.type.SortBy import com.terning.domain.entity.search.SearchResult data class SearchProcessState( val loadState: UiState = UiState.Loading, + val currentSortBy: Int = 0, val text: String = "", val keyword: String = "", - val sortBy: String = "", + val sortBy: SortBy = SortBy.EARLIEST, val page: Int = 0, val size: Int = 10, val showSearchResults: Boolean = false, @@ -16,6 +18,7 @@ data class SearchProcessState( val scrapped: Boolean = false, val selectedInternIndex: Int = 0, val sheetState: Boolean = false, + val changeFilterState: Boolean = false, val searchResult: SearchResult = SearchResult( internshipAnnouncementId = 0, title = "", From f8300e5bdafeb84897092c28700e811823cedc75 Mon Sep 17 00:00:00 2001 From: arinming Date: Sun, 15 Sep 2024 03:04:24 +0900 Subject: [PATCH 08/14] =?UTF-8?q?[FIX/#250]=20updateExistSearchResults=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../feature/search/searchprocess/SearchProcessRoute.kt | 3 +-- .../search/searchprocess/SearchProcessViewModel.kt | 9 ++------- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessRoute.kt b/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessRoute.kt index a4f000a03..83db9f040 100644 --- a/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessRoute.kt +++ b/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessRoute.kt @@ -68,7 +68,6 @@ fun SearchProcessRoute( LaunchedEffect(true) { viewModel.getSearchList( keyword = state.text, - sortBy = state.currentSortBy, page = 0, size = 10 ) @@ -97,13 +96,13 @@ fun SearchProcessRoute( viewModel.updateText(it) }, onSearchAction = { + viewModel.updateQuery(state.text) viewModel.getSearchList( keyword = state.text, sortBy = state.currentSortBy, page = 0, size = 10, ) - viewModel.updateQuery(state.text) viewModel.updateShowSearchResults(true) viewModel.updateExistSearchResults(state.text) }, diff --git a/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessViewModel.kt b/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessViewModel.kt index 08280467d..cc2879aed 100644 --- a/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessViewModel.kt +++ b/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessViewModel.kt @@ -34,13 +34,10 @@ class SearchProcessViewModel @Inject constructor( _internSearchResultData.asStateFlow() fun getSearchList( keyword: String, - sortBy: Int, + sortBy: Int = 0, page: Int, size: Int, ) { - if (sortBy < 0 || sortBy >= SortBy.entries.size) { - return - } viewModelScope.launch { searchRepository.getSearchList(keyword, SortBy.entries[sortBy].type, page, size) .onSuccess { results -> @@ -93,9 +90,7 @@ class SearchProcessViewModel @Inject constructor( } fun updateExistSearchResults(query: String) { - val exists = - _internSearchResultData.value.any { it.title.contains(query, ignoreCase = true) } - _state.update { it.copy(existSearchResults = exists) } + _state.update { it.copy(existSearchResults = _internSearchResultData.value.isNotEmpty()) } } fun updateScrapDialogVisible(visible: Boolean) { From c4df49a4f8eab34bf193031d0af8c37ceb2d9009 Mon Sep 17 00:00:00 2001 From: arinming Date: Sun, 15 Sep 2024 23:51:06 +0900 Subject: [PATCH 09/14] =?UTF-8?q?[FIX/#250]=20=EA=B4=91=EA=B3=A0=20?= =?UTF-8?q?=EB=84=98=EA=B8=B0=EA=B8=B0=20=ED=9A=A8=EA=B3=BC=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../search/search/component/ImageSlider.kt | 18 +++++++++++++----- .../search/searchprocess/SearchProcessRoute.kt | 4 ++-- .../searchprocess/models/SearchProcessState.kt | 2 +- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/feature/src/main/java/com/terning/feature/search/search/component/ImageSlider.kt b/feature/src/main/java/com/terning/feature/search/search/component/ImageSlider.kt index b6384976a..4328dfb90 100644 --- a/feature/src/main/java/com/terning/feature/search/search/component/ImageSlider.kt +++ b/feature/src/main/java/com/terning/feature/search/search/component/ImageSlider.kt @@ -11,6 +11,8 @@ import androidx.compose.foundation.pager.HorizontalPager import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.layout.ContentScale @@ -25,14 +27,20 @@ fun ImageSlider( images: List, ) { val pagerState = rememberPagerState(pageCount = { images.size }) + val autoScroll = remember { mutableStateOf(true) } - LaunchedEffect(Unit) { - while (true) { - delay(3000) - val nextPage = (pagerState.currentPage + 1) % pagerState.pageCount - pagerState.scrollToPage(nextPage) + LaunchedEffect(autoScroll.value) { + if (autoScroll.value) { + while (true) { + delay(2000) + if (!pagerState.isScrollInProgress) { + val nextPage = (pagerState.currentPage + 1) % pagerState.pageCount + pagerState.animateScrollToPage(nextPage) + } + } } } + Column( modifier .fillMaxWidth() diff --git a/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessRoute.kt b/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessRoute.kt index 83db9f040..a20c86ae4 100644 --- a/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessRoute.kt +++ b/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessRoute.kt @@ -69,7 +69,7 @@ fun SearchProcessRoute( viewModel.getSearchList( keyword = state.text, page = 0, - size = 10 + size = 100 ) } @@ -101,7 +101,7 @@ fun SearchProcessRoute( keyword = state.text, sortBy = state.currentSortBy, page = 0, - size = 10, + size = 100, ) viewModel.updateShowSearchResults(true) viewModel.updateExistSearchResults(state.text) diff --git a/feature/src/main/java/com/terning/feature/search/searchprocess/models/SearchProcessState.kt b/feature/src/main/java/com/terning/feature/search/searchprocess/models/SearchProcessState.kt index 394edd35f..a397cd2c8 100644 --- a/feature/src/main/java/com/terning/feature/search/searchprocess/models/SearchProcessState.kt +++ b/feature/src/main/java/com/terning/feature/search/searchprocess/models/SearchProcessState.kt @@ -11,7 +11,7 @@ data class SearchProcessState( val keyword: String = "", val sortBy: SortBy = SortBy.EARLIEST, val page: Int = 0, - val size: Int = 10, + val size: Int = 100, val showSearchResults: Boolean = false, val existSearchResults: Boolean = false, val isScrapDialogVisible: Boolean = false, From da9b2ca4bc5e9450082826650c4a0c43aab93297 Mon Sep 17 00:00:00 2001 From: arinming Date: Sun, 15 Sep 2024 23:59:55 +0900 Subject: [PATCH 10/14] =?UTF-8?q?[FIX/#250]=20=EB=B2=84=EA=B7=B8=20?= =?UTF-8?q?=EB=B0=8F=20=EC=95=88=EC=93=B0=EB=8A=94=20=EC=9E=84=ED=8F=AC?= =?UTF-8?q?=ED=8A=B8=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/terning/feature/search/search/component/ImageSlider.kt | 1 - .../terning/feature/search/searchprocess/SearchProcessRoute.kt | 3 ++- .../feature/search/searchprocess/SearchProcessViewModel.kt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/feature/src/main/java/com/terning/feature/search/search/component/ImageSlider.kt b/feature/src/main/java/com/terning/feature/search/search/component/ImageSlider.kt index 4328dfb90..42e92a00e 100644 --- a/feature/src/main/java/com/terning/feature/search/search/component/ImageSlider.kt +++ b/feature/src/main/java/com/terning/feature/search/search/component/ImageSlider.kt @@ -6,7 +6,6 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding import androidx.compose.foundation.pager.HorizontalPager import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.runtime.Composable diff --git a/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessRoute.kt b/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessRoute.kt index a20c86ae4..5faaa3ffe 100644 --- a/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessRoute.kt +++ b/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessRoute.kt @@ -168,6 +168,7 @@ fun SearchProcessScreen( ) { val focusRequester = remember { FocusRequester() } val focusManager = LocalFocusManager.current + val currentSortBy = remember { mutableIntStateOf(state.currentSortBy) } LaunchedEffect(Unit) { focusRequester.requestFocus() @@ -327,7 +328,7 @@ fun SearchProcessScreen( SortingBottomSheet( currentSortBy = state.currentSortBy, onDismiss = onDismissSheet, - newSortBy = mutableIntStateOf(state.currentSortBy), + newSortBy = currentSortBy, onSortChange = onSortChange ) } diff --git a/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessViewModel.kt b/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessViewModel.kt index cc2879aed..6bc552661 100644 --- a/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessViewModel.kt +++ b/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessViewModel.kt @@ -107,7 +107,7 @@ class SearchProcessViewModel @Inject constructor( keyword = _state.value.keyword, sortBy = newSortBy, page = 0, - size = 10 + size = 100 ) } } From 9c831b587a5c34ea49d4db5eeb6e2fa900c9f996 Mon Sep 17 00:00:00 2001 From: arinming Date: Mon, 16 Sep 2024 00:00:21 +0900 Subject: [PATCH 11/14] =?UTF-8?q?[DELETE/#250]=20=EC=95=88=EC=93=B0?= =?UTF-8?q?=EB=8A=94=20=ED=8C=8C=EB=9D=BC=EB=AF=B8=ED=84=B0=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../feature/search/searchprocess/SearchProcessViewModel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessViewModel.kt b/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessViewModel.kt index 6bc552661..e88900c36 100644 --- a/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessViewModel.kt +++ b/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessViewModel.kt @@ -89,7 +89,7 @@ class SearchProcessViewModel @Inject constructor( _state.update { it.copy(showSearchResults = show, existSearchResults = true) } } - fun updateExistSearchResults(query: String) { + fun updateExistSearchResults() { _state.update { it.copy(existSearchResults = _internSearchResultData.value.isNotEmpty()) } } From 4b7abffaa40adca0406be49c140f004e41c88d2f Mon Sep 17 00:00:00 2001 From: arinming Date: Mon, 16 Sep 2024 03:12:58 +0900 Subject: [PATCH 12/14] =?UTF-8?q?[FIX/#250]=20=ED=8C=8C=EB=9D=BC=EB=AF=B8?= =?UTF-8?q?=ED=84=B0=20=EA=B4=80=EB=A0=A8=20=EC=98=A4=EB=A5=98=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../terning/feature/search/searchprocess/SearchProcessRoute.kt | 2 +- .../feature/search/searchprocess/SearchProcessViewModel.kt | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessRoute.kt b/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessRoute.kt index 5faaa3ffe..b27fa9f58 100644 --- a/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessRoute.kt +++ b/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessRoute.kt @@ -104,7 +104,7 @@ fun SearchProcessRoute( size = 100, ) viewModel.updateShowSearchResults(true) - viewModel.updateExistSearchResults(state.text) + viewModel.updateExistSearchResults() }, onSortButtonClick = { viewModel.updateSheetVisible(true) diff --git a/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessViewModel.kt b/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessViewModel.kt index e88900c36..e912c4de8 100644 --- a/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessViewModel.kt +++ b/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessViewModel.kt @@ -32,6 +32,7 @@ class SearchProcessViewModel @Inject constructor( private val _internSearchResultData = MutableStateFlow>(emptyList()) val internSearchResultData: StateFlow> = _internSearchResultData.asStateFlow() + fun getSearchList( keyword: String, sortBy: Int = 0, From daa9dbe954d15ff1210c16e4a7a0c4bcbf4cd2db Mon Sep 17 00:00:00 2001 From: arinming Date: Mon, 16 Sep 2024 03:52:19 +0900 Subject: [PATCH 13/14] =?UTF-8?q?[FIX/#250]=20=EC=8A=A4=ED=81=AC=EB=9E=A9?= =?UTF-8?q?=20=EB=8B=A4=EC=9D=B4=EC=96=BC=EB=A1=9C=EA=B7=B8=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../calendar/list/CalendarListScreen.kt | 2 +- .../calendar/week/CalendarWeekScreen.kt | 2 +- .../feature/dialog/detail/ScrapDialog.kt | 16 +++---- .../com/terning/feature/intern/InternRoute.kt | 2 +- .../searchprocess/SearchProcessRoute.kt | 44 +++++++++---------- .../searchprocess/SearchProcessViewModel.kt | 10 +++++ 6 files changed, 43 insertions(+), 33 deletions(-) diff --git a/feature/src/main/java/com/terning/feature/calendar/list/CalendarListScreen.kt b/feature/src/main/java/com/terning/feature/calendar/list/CalendarListScreen.kt index 6e145abbc..59189d662 100644 --- a/feature/src/main/java/com/terning/feature/calendar/list/CalendarListScreen.kt +++ b/feature/src/main/java/com/terning/feature/calendar/list/CalendarListScreen.kt @@ -125,7 +125,7 @@ private fun CalendarListScreen( uiState: CalendarListUiState, navigateToAnnouncement: (Long) -> Unit, onDismissCancelDialog: (Boolean) -> Unit, - onDismissInternDialog: () -> Unit, + onDismissInternDialog: (Boolean) -> Unit, onClickChangeColor: () -> Unit, onClickInternship: (CalendarScrapDetail) -> Unit, onClickScrapButton: (Long) -> Unit, diff --git a/feature/src/main/java/com/terning/feature/calendar/week/CalendarWeekScreen.kt b/feature/src/main/java/com/terning/feature/calendar/week/CalendarWeekScreen.kt index ca882549f..bfc8bf56b 100644 --- a/feature/src/main/java/com/terning/feature/calendar/week/CalendarWeekScreen.kt +++ b/feature/src/main/java/com/terning/feature/calendar/week/CalendarWeekScreen.kt @@ -121,7 +121,7 @@ private fun CalendarWeekScreen( selectedDate: LocalDate, updateSelectedDate: (LocalDate) -> Unit, onDismissCancelDialog: (Boolean) -> Unit, - onDismissInternDialog: () -> Unit, + onDismissInternDialog: (Boolean) -> Unit, onClickChangeColor: () -> Unit, onClickInternship: (CalendarScrapDetail) -> Unit, onClickScrapButton: (Long) -> Unit, diff --git a/feature/src/main/java/com/terning/feature/dialog/detail/ScrapDialog.kt b/feature/src/main/java/com/terning/feature/dialog/detail/ScrapDialog.kt index 0928b1cc8..fbca9cf37 100644 --- a/feature/src/main/java/com/terning/feature/dialog/detail/ScrapDialog.kt +++ b/feature/src/main/java/com/terning/feature/dialog/detail/ScrapDialog.kt @@ -64,11 +64,11 @@ fun ScrapDialog( internshipAnnouncementId: Long, companyImage: String, isScrapped: Boolean, - onDismissRequest: () -> Unit = {}, + onDismissRequest: (Boolean) -> Unit = {}, onScrapAnnouncement: () -> Unit = {}, onClickChangeColor: () -> Unit = {}, onClickNavigateButton: (Long) -> Unit = {}, - viewModel: ScrapDialogViewModel = hiltViewModel() + viewModel: ScrapDialogViewModel = hiltViewModel(), ) { val context = LocalContext.current val lifecycleOwner = LocalLifecycleOwner.current @@ -83,12 +83,12 @@ fun ScrapDialog( is ScrapDialogSideEffect.DismissDialog -> { viewModel.initUiState() - onDismissRequest() + onDismissRequest(false) } is ScrapDialogSideEffect.PatchedScrap -> { onClickChangeColor() - onDismissRequest() + onDismissRequest(false) } is ScrapDialogSideEffect.NavigateToDetail -> onClickNavigateButton( @@ -97,7 +97,7 @@ fun ScrapDialog( is ScrapDialogSideEffect.ScrappedAnnouncement -> { onScrapAnnouncement() - onDismissRequest() + onDismissRequest(true) } } } @@ -150,7 +150,7 @@ private fun ScrapDialogScreen( onClickColorButton: (ColorType) -> Unit, onClickNavigateButton: () -> Unit, onClickColorChangeButton: () -> Unit, - onClickScrapButton: () -> Unit + onClickScrapButton: () -> Unit, ) { Box( modifier = Modifier @@ -277,7 +277,7 @@ private fun ScrapDialogScreen( @Composable private fun NewScrapButton( onClickScrapButton: () -> Unit, - modifier: Modifier = Modifier + modifier: Modifier = Modifier, ) { RoundButton( style = TerningTheme.typography.button3, @@ -294,7 +294,7 @@ private fun DetailScrapButton( isColorChanged: Boolean, onClickNavigateButton: () -> Unit, onClickColorChangeButton: () -> Unit, - modifier: Modifier = Modifier + modifier: Modifier = Modifier, ) { Row( modifier = modifier diff --git a/feature/src/main/java/com/terning/feature/intern/InternRoute.kt b/feature/src/main/java/com/terning/feature/intern/InternRoute.kt index ef02c79ed..30e877e99 100644 --- a/feature/src/main/java/com/terning/feature/intern/InternRoute.kt +++ b/feature/src/main/java/com/terning/feature/intern/InternRoute.kt @@ -104,7 +104,7 @@ fun InternScreen( internUiState: InternUiState, internInfo: InternInfo, onDismissCancelDialog: (Boolean) -> Unit, - onDismissScrapDialog: () -> Unit, + onDismissScrapDialog: (Boolean) -> Unit, onClickCancelButton: (InternInfo) -> Unit, onClickScrapButton: (InternInfo) -> Unit, ) { diff --git a/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessRoute.kt b/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessRoute.kt index b27fa9f58..ac7e3659d 100644 --- a/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessRoute.kt +++ b/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessRoute.kt @@ -69,7 +69,7 @@ fun SearchProcessRoute( viewModel.getSearchList( keyword = state.text, page = 0, - size = 100 + size = 0 ) } @@ -109,23 +109,19 @@ fun SearchProcessRoute( onSortButtonClick = { viewModel.updateSheetVisible(true) }, - onDismissCancelDialog = { - viewModel.getSearchList( - keyword = state.keyword, - sortBy = state.sortBy.ordinal, - page = state.page, - size = state.size - ) + onDismissScrapDialog = { isScrapped, searchResult -> viewModel.updateScrapDialogVisible(false) - }, - onDismissScrapDialog = { - viewModel.getSearchList( - keyword = state.keyword, - sortBy = state.sortBy.ordinal, - page = state.page, - size = state.size + viewModel.updateSearchResultScrapStatus( + searchResult.internshipAnnouncementId, + isScrapped ) + }, + onDismissCancelDialog = { isScrapped, searchResult -> viewModel.updateScrapDialogVisible(false) + viewModel.updateSearchResultScrapStatus( + searchResult.internshipAnnouncementId, + !isScrapped + ) }, onDismissSheet = { viewModel.updateSheetVisible(false) @@ -160,8 +156,8 @@ fun SearchProcessScreen( updateText: (String) -> Unit = {}, onSearchAction: () -> Unit = {}, onSortButtonClick: () -> Unit = {}, - onDismissCancelDialog: (Boolean) -> Unit, - onDismissScrapDialog: () -> Unit, + onDismissCancelDialog: (Boolean, SearchResult) -> Unit, + onDismissScrapDialog: (Boolean, SearchResult) -> Unit, onDismissSheet: () -> Unit = {}, onScrapButtonClicked: (SearchResult) -> Unit, onSortChange: (Int) -> Unit = {}, @@ -223,8 +219,6 @@ fun SearchProcessScreen( horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center ) { - - Row( horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically, @@ -270,7 +264,9 @@ fun SearchProcessScreen( intern = internSearchResultData[index], navigateToIntern = navigateToIntern, onScrapButtonClicked = { - onScrapButtonClicked(internSearchResultData[index]) + with(internSearchResultData[index]) { + onScrapButtonClicked(this) + } } ) } @@ -338,7 +334,9 @@ fun SearchProcessScreen( if (searchResult.isScrapped) { ScrapCancelDialog( internshipAnnouncementId = searchResult.internshipAnnouncementId, - onDismissRequest = onDismissCancelDialog + onDismissRequest = { isScrapped -> + onDismissCancelDialog(isScrapped, searchResult) + } ) } else { ScrapDialog( @@ -350,7 +348,9 @@ fun SearchProcessScreen( internshipAnnouncementId = searchResult.internshipAnnouncementId, companyImage = searchResult.companyImage, isScrapped = false, - onDismissRequest = onDismissScrapDialog, + onDismissRequest = { isScrapped -> + onDismissScrapDialog(isScrapped, searchResult) + } ) } } diff --git a/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessViewModel.kt b/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessViewModel.kt index e912c4de8..c2aeb5d59 100644 --- a/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessViewModel.kt +++ b/feature/src/main/java/com/terning/feature/search/searchprocess/SearchProcessViewModel.kt @@ -111,4 +111,14 @@ class SearchProcessViewModel @Inject constructor( size = 100 ) } + + fun updateSearchResultScrapStatus(internshipId: Long, isScrapped: Boolean) { + _internSearchResultData.value = _internSearchResultData.value.map { searchResult -> + if (searchResult.internshipAnnouncementId == internshipId) { + searchResult.copy(isScrapped = isScrapped) + } else { + searchResult + } + } + } } From edf7c63a6132a296dc0a8536fce2c0e3308f96a9 Mon Sep 17 00:00:00 2001 From: arinming Date: Wed, 18 Sep 2024 21:23:36 +0900 Subject: [PATCH 14/14] =?UTF-8?q?[FIX/#250]=20=EC=BA=98=EB=A6=B0=EB=8D=94?= =?UTF-8?q?=20=EC=8A=A4=ED=81=AC=EB=9E=A9=20=ED=95=A8=EC=88=98=20Boolean?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../feature/calendar/list/CalendarListScreen.kt | 10 +++++----- .../feature/calendar/week/CalendarWeekScreen.kt | 12 ++++++------ 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/feature/src/main/java/com/terning/feature/calendar/list/CalendarListScreen.kt b/feature/src/main/java/com/terning/feature/calendar/list/CalendarListScreen.kt index cddf094bd..fd9dcb544 100644 --- a/feature/src/main/java/com/terning/feature/calendar/list/CalendarListScreen.kt +++ b/feature/src/main/java/com/terning/feature/calendar/list/CalendarListScreen.kt @@ -51,7 +51,7 @@ fun CalendarListRoute( modifier: Modifier = Modifier, navigateUp: () -> Unit, navigateToAnnouncement: (Long) -> Unit, - viewModel: CalendarListViewModel = hiltViewModel() + viewModel: CalendarListViewModel = hiltViewModel(), ) { val pagerState = LocalPagerState.current val lifecycleOwner = LocalLifecycleOwner.current @@ -130,7 +130,7 @@ private fun CalendarListScreen( uiState: CalendarListUiState, onClickInternship: (CalendarScrapDetail) -> Unit, onClickScrapButton: (Long) -> Unit, - modifier: Modifier = Modifier + modifier: Modifier = Modifier, ) { HorizontalPager( state = pagerState, @@ -195,7 +195,7 @@ private fun CalendarListScreen( @Composable private fun CalendarListEmpty( - modifier: Modifier = Modifier + modifier: Modifier = Modifier, ) { Image( painter = painterResource( @@ -218,7 +218,7 @@ private fun CalendarListEmpty( private fun CalendarListScrapCancelDialog( scrapVisibility: Boolean, internshipAnnouncementId: Long?, - onDismissCancelDialog: (Boolean) -> Unit + onDismissCancelDialog: (Boolean) -> Unit, ) { if (scrapVisibility) { internshipAnnouncementId?.run { @@ -236,7 +236,7 @@ private fun CalendarListScrapPatchDialog( dialogVisibility: Boolean, internshipModel: CalendarScrapDetail?, navigateToAnnouncement: (Long) -> Unit, - onDismissInternDialog: () -> Unit, + onDismissInternDialog: (Boolean) -> Unit, onClickChangeColor: () -> Unit, ) { if (dialogVisibility) { diff --git a/feature/src/main/java/com/terning/feature/calendar/week/CalendarWeekScreen.kt b/feature/src/main/java/com/terning/feature/calendar/week/CalendarWeekScreen.kt index 206530448..3bad48937 100644 --- a/feature/src/main/java/com/terning/feature/calendar/week/CalendarWeekScreen.kt +++ b/feature/src/main/java/com/terning/feature/calendar/week/CalendarWeekScreen.kt @@ -60,7 +60,7 @@ fun CalendarWeekRoute( updateSelectedDate: (LocalDate) -> Unit, navigateUp: () -> Unit, modifier: Modifier = Modifier, - viewModel: CalendarWeekViewModel = hiltViewModel() + viewModel: CalendarWeekViewModel = hiltViewModel(), ) { val pagerState = LocalPagerState.current val lifecycleOwner = LocalLifecycleOwner.current @@ -138,7 +138,7 @@ private fun CalendarWeekScreen( updateSelectedDate: (LocalDate) -> Unit, onClickInternship: (CalendarScrapDetail) -> Unit, onClickScrapButton: (Long) -> Unit, - modifier: Modifier = Modifier + modifier: Modifier = Modifier, ) { var swiped by remember { mutableStateOf(false) } @@ -216,7 +216,7 @@ private fun CalendarWeekScreen( @Composable private fun CalendarWeekEmpty( - modifier: Modifier = Modifier + modifier: Modifier = Modifier, ) { Image( painter = painterResource( @@ -241,7 +241,7 @@ private fun CalendarWeekSuccess( scrapList: List, onScrapButtonClicked: (Long) -> Unit, onInternshipClicked: (CalendarScrapDetail) -> Unit, - selectedDate: LocalDate + selectedDate: LocalDate, ) { CalendarScrapList( selectedDate = selectedDate, @@ -257,7 +257,7 @@ private fun CalendarWeekSuccess( private fun CalendarWeekScrapCancelDialog( scrapVisibility: Boolean, internshipAnnouncementId: Long?, - onDismissCancelDialog: (Boolean) -> Unit + onDismissCancelDialog: (Boolean) -> Unit, ) { if (scrapVisibility) { internshipAnnouncementId?.run { @@ -275,7 +275,7 @@ private fun CalendarWeekScrapPatchDialog( dialogVisibility: Boolean, internshipModel: CalendarScrapDetail?, navigateToAnnouncement: (Long) -> Unit, - onDismissInternDialog: () -> Unit, + onDismissInternDialog: (Boolean) -> Unit, onClickChangeColor: () -> Unit, ) { if (dialogVisibility) {