From 4865189f869dea2fbf0cb5d3a4a07692523d8a62 Mon Sep 17 00:00:00 2001 From: Seongjun Jo Date: Mon, 4 Dec 2023 17:31:06 +0900 Subject: [PATCH 01/12] fix: post regulation * fix regex to include white space * increase the content length limit --- .../example/haengsha/ui/screens/board/BoardPostScreen.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/frontend/app/src/main/java/com/example/haengsha/ui/screens/board/BoardPostScreen.kt b/frontend/app/src/main/java/com/example/haengsha/ui/screens/board/BoardPostScreen.kt index e7d6a9a..35f2201 100644 --- a/frontend/app/src/main/java/com/example/haengsha/ui/screens/board/BoardPostScreen.kt +++ b/frontend/app/src/main/java/com/example/haengsha/ui/screens/board/BoardPostScreen.kt @@ -648,14 +648,14 @@ private fun checkPostFormat( eventTime: String, eventContent: String ): String { - val noSpecialCharacterRegex = "^[a-zA-Zㄱ-ㅎㅏ-ㅣ가-힣\\d]+$".toRegex() + val noSpecialCharacterRegex = "^[a-zA-Zㄱ-ㅎㅏ-ㅣ가-힣\\d\\s]+$".toRegex() val possibleRegexPattern = "^[0-9a-zA-Zㄱ-ㅎㅏ-ㅣ가-힣+×÷=/_<>\\[\\]!@#\$%^&*()\\-'\":;?`~\\\\|{}€£¥₩♤♡◇♧☆▪︎¤《》¡¿°•○●□■.,‽±』」〕】『「〔【№₽٪‰‐—–♠♥◆♣★\\s\\n]+$".toRegex() if (eventTitle.startsWith(" ") || eventTitle.endsWith(" ")) { return "제목의 앞뒤 공백을 제거해주세요." } else if (eventTitle.length !in 2..20) { - return "제목은 2자 이상 20자 이하로 입력해주세요." + return "제목은 2자 이상 40자 이하로 입력해주세요." } else if (!possibleRegexPattern.matches(eventTitle)) { return "제목은 한글, 영어, 숫자, 특수문자로만 입력해주세요.\n아직 이모지는 사용할 수 없습니다." } @@ -694,8 +694,8 @@ private fun checkPostFormat( if (eventContent.trim().isEmpty()) { return "내용을 입력해주세요." - } else if (eventContent.length !in 2..1000) { - return "내용은 2자 이상 1000자 이하로 입력해주세요." + } else if (eventContent.length !in 2..2000) { + return "내용은 2자 이상 2000자 이하로 입력해주세요." } else if (!possibleRegexPattern.matches(eventContent)) { return "내용은 한글, 영어, 숫자, 특수문자로만 입력해주세요.\n아직 이모지는 사용할 수 없습니다." } From 6757b02d700d1309d8de9fdfaf1f74d4453f017a Mon Sep 17 00:00:00 2001 From: Seongjun Jo Date: Mon, 4 Dec 2023 18:19:02 +0900 Subject: [PATCH 02/12] fix: handle filtering edge case * prevent filtering after changing input with not search --- .../model/viewModel/board/BoardViewModel.kt | 18 ++++++++++++++++++ .../haengsha/ui/uiComponents/CustomDialog.kt | 12 ++++++++++++ .../ui/uiComponents/CustomTextField.kt | 6 +++++- 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/frontend/app/src/main/java/com/example/haengsha/model/viewModel/board/BoardViewModel.kt b/frontend/app/src/main/java/com/example/haengsha/model/viewModel/board/BoardViewModel.kt index bf250be..f874295 100644 --- a/frontend/app/src/main/java/com/example/haengsha/model/viewModel/board/BoardViewModel.kt +++ b/frontend/app/src/main/java/com/example/haengsha/model/viewModel/board/BoardViewModel.kt @@ -17,10 +17,28 @@ class BoardViewModel : ViewModel() { private val _eventId = MutableStateFlow(0) val eventId = _eventId.asStateFlow() + private val _input = MutableStateFlow("") + val input = _input.asStateFlow() + + private val _isSearched = MutableStateFlow(false) + val isSearched = _isSearched.asStateFlow() + fun updateEventId(newEventId: Int) { _eventId.value = newEventId } + fun updateInput(newInput: String) { + _input.value = newInput + } + + fun setIsSearchedTrue() { + _isSearched.value = true + } + + fun setIsSearchedFalse() { + _isSearched.value = false + } + var isError = false fun isError() { diff --git a/frontend/app/src/main/java/com/example/haengsha/ui/uiComponents/CustomDialog.kt b/frontend/app/src/main/java/com/example/haengsha/ui/uiComponents/CustomDialog.kt index 6491d74..f0755e2 100644 --- a/frontend/app/src/main/java/com/example/haengsha/ui/uiComponents/CustomDialog.kt +++ b/frontend/app/src/main/java/com/example/haengsha/ui/uiComponents/CustomDialog.kt @@ -172,6 +172,10 @@ fun FilterDialog( ) { val isFestival = boardUiState.isFestival + if (boardViewModel.input.value != boardUiState.keyword) { + boardViewModel.setIsSearchedFalse() + } + Dialog(onDismissRequest = onDismissRequest) { Box( modifier = Modifier.fillMaxSize(), @@ -379,6 +383,14 @@ fun FilterDialog( Toasty.warning(context, "검색 후 필터를 적용해주세요", Toast.LENGTH_SHORT, true) .show() boardViewModel.resetFilterInitialState() + } else if (!boardViewModel.isSearched.value) { + Toasty.warning( + context, + "검색 완료 후 필터를 적용해주세요", + Toast.LENGTH_SHORT, + true + ) + .show() } else { onSubmit( SearchRequest( diff --git a/frontend/app/src/main/java/com/example/haengsha/ui/uiComponents/CustomTextField.kt b/frontend/app/src/main/java/com/example/haengsha/ui/uiComponents/CustomTextField.kt index e88c92c..7afbe2e 100644 --- a/frontend/app/src/main/java/com/example/haengsha/ui/uiComponents/CustomTextField.kt +++ b/frontend/app/src/main/java/com/example/haengsha/ui/uiComponents/CustomTextField.kt @@ -371,7 +371,10 @@ fun SearchBar( .padding(start = 30.dp, end = 30.dp) .testTag(stringResource(R.string.searchBar)), value = input, - onValueChange = { input = it }, + onValueChange = { + input = it + boardViewModel.updateInput(input) + }, placeholder = { Text( text = "Search", @@ -402,6 +405,7 @@ fun SearchBar( .show() } else { boardViewModel.updateKeyword(input) + boardViewModel.setIsSearchedTrue() onSubmit( SearchRequest( boardViewModel.boardUiState.value.token, From be73e49905d9d41d7b859de17671aa8babfe79dd Mon Sep 17 00:00:00 2001 From: Seongjun Jo Date: Mon, 4 Dec 2023 20:02:49 +0900 Subject: [PATCH 03/12] fix: search warning toast text --- .../com/example/haengsha/ui/uiComponents/CustomTextField.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/app/src/main/java/com/example/haengsha/ui/uiComponents/CustomTextField.kt b/frontend/app/src/main/java/com/example/haengsha/ui/uiComponents/CustomTextField.kt index 7afbe2e..b137bef 100644 --- a/frontend/app/src/main/java/com/example/haengsha/ui/uiComponents/CustomTextField.kt +++ b/frontend/app/src/main/java/com/example/haengsha/ui/uiComponents/CustomTextField.kt @@ -401,7 +401,7 @@ fun SearchBar( Toasty.warning(context, "2자에서 50자 사이로 검색해주세요", Toast.LENGTH_SHORT, true) .show() } else if (!possibleRegexPattern.matches(input)) { - Toasty.warning(context, "한글, 영어, 숫자로만 검색해주세요", Toast.LENGTH_SHORT, true) + Toasty.warning(context, "한글, 영어, 숫자, 특수문자로만 검색해주세요", Toast.LENGTH_SHORT, true) .show() } else { boardViewModel.updateKeyword(input) From 621c42a7ffc5134307afc629250ea1dc4ca9db70 Mon Sep 17 00:00:00 2001 From: Seongjun Jo Date: Tue, 5 Dec 2023 15:14:21 +0900 Subject: [PATCH 04/12] fix: optimization * delete unused file * delete useless annotation * optimize variable type --- .../haengsha/model/dataSource/AppContainer.kt | 2 +- .../haengsha/model/dataSource/DateInfo.kt | 159 ------------------ .../model/uiState/board/BoardApiUiState.kt | 42 ++--- .../model/uiState/home/HomeApiUiState.kt | 10 +- .../uiState/home/RecommendationApiUiState.kt | 8 +- 5 files changed, 31 insertions(+), 190 deletions(-) delete mode 100644 frontend/app/src/main/java/com/example/haengsha/model/dataSource/DateInfo.kt diff --git a/frontend/app/src/main/java/com/example/haengsha/model/dataSource/AppContainer.kt b/frontend/app/src/main/java/com/example/haengsha/model/dataSource/AppContainer.kt index 8ba655c..c2c084a 100644 --- a/frontend/app/src/main/java/com/example/haengsha/model/dataSource/AppContainer.kt +++ b/frontend/app/src/main/java/com/example/haengsha/model/dataSource/AppContainer.kt @@ -18,7 +18,7 @@ interface AppContainer { class HaengshaAppContainer : AppContainer { private val baseUrl = "http://ec2-13-209-8-183.ap-northeast-2.compute.amazonaws.com:8080/" - // private val baseUrl = "http://10.150.196.98:8000" + private val httpLoggingInterceptor = HttpLoggingInterceptor().apply { level = HttpLoggingInterceptor.Level.BODY } diff --git a/frontend/app/src/main/java/com/example/haengsha/model/dataSource/DateInfo.kt b/frontend/app/src/main/java/com/example/haengsha/model/dataSource/DateInfo.kt deleted file mode 100644 index 45d2272..0000000 --- a/frontend/app/src/main/java/com/example/haengsha/model/dataSource/DateInfo.kt +++ /dev/null @@ -1,159 +0,0 @@ -package com.example.haengsha.model.dataSource - -object DateInfo { - val year = listOf( - "2023년", - "2024년", - "2025년", - "2026년", - "2027년", - "2028년", - "2029년", - "2030년" - ) - - val month = listOf( - "1월", - "2월", - "3월", - "4월", - "5월", - "6월", - "7월", - "8월", - "9월", - "10월", - "11월", - "12월" - ) - - val oddMonthDate = listOf( - "1일", - "2일", - "3일", - "4일", - "5일", - "6일", - "7일", - "8일", - "9일", - "10일", - "11일", - "12일", - "13일", - "14일", - "15일", - "16일", - "17일", - "18일", - "19일", - "20일", - "21일", - "22일", - "23일", - "24일", - "25일", - "26일", - "27일", - "28일", - "29일", - "30일", - "31일" - ) - - val evenMonthDate = listOf( - "1일", - "2일", - "3일", - "4일", - "5일", - "6일", - "7일", - "8일", - "9일", - "10일", - "11일", - "12일", - "13일", - "14일", - "15일", - "16일", - "17일", - "18일", - "19일", - "20일", - "21일", - "22일", - "23일", - "24일", - "25일", - "26일", - "27일", - "28일", - "29일", - "30일" - ) - - val februaryDate = listOf( - "1일", - "2일", - "3일", - "4일", - "5일", - "6일", - "7일", - "8일", - "9일", - "10일", - "11일", - "12일", - "13일", - "14일", - "15일", - "16일", - "17일", - "18일", - "19일", - "20일", - "21일", - "22일", - "23일", - "24일", - "25일", - "26일", - "27일", - "28일" - ) - - val leapYearDate = listOf( - "1일", - "2일", - "3일", - "4일", - "5일", - "6일", - "7일", - "8일", - "9일", - "10일", - "11일", - "12일", - "13일", - "14일", - "15일", - "16일", - "17일", - "18일", - "19일", - "20일", - "21일", - "22일", - "23일", - "24일", - "25일", - "26일", - "27일", - "28일", - "29일" - ) -} \ No newline at end of file diff --git a/frontend/app/src/main/java/com/example/haengsha/model/uiState/board/BoardApiUiState.kt b/frontend/app/src/main/java/com/example/haengsha/model/uiState/board/BoardApiUiState.kt index 451f6cc..b283c10 100644 --- a/frontend/app/src/main/java/com/example/haengsha/model/uiState/board/BoardApiUiState.kt +++ b/frontend/app/src/main/java/com/example/haengsha/model/uiState/board/BoardApiUiState.kt @@ -8,10 +8,10 @@ sealed interface BoardListUiState { val boardList: List ) : BoardListUiState - object HttpError : BoardListUiState - object NetworkError : BoardListUiState - object Error : BoardListUiState - object Loading : BoardListUiState + data object HttpError : BoardListUiState + data object NetworkError : BoardListUiState + data object Error : BoardListUiState + data object Loading : BoardListUiState } sealed interface BoardFavoriteUiState { @@ -19,10 +19,10 @@ sealed interface BoardFavoriteUiState { val boardList: List ) : BoardFavoriteUiState - object HttpError : BoardFavoriteUiState - object NetworkError : BoardFavoriteUiState - object Error : BoardFavoriteUiState - object Loading : BoardFavoriteUiState + data object HttpError : BoardFavoriteUiState + data object NetworkError : BoardFavoriteUiState + data object Error : BoardFavoriteUiState + data object Loading : BoardFavoriteUiState } sealed interface BoardDetailUiState { @@ -30,18 +30,18 @@ sealed interface BoardDetailUiState { val boardDetail: BoardDetailResponse ) : BoardDetailUiState - object HttpError : BoardDetailUiState - object NetworkError : BoardDetailUiState - object Error : BoardDetailUiState - object Loading : BoardDetailUiState + data object HttpError : BoardDetailUiState + data object NetworkError : BoardDetailUiState + data object Error : BoardDetailUiState + data object Loading : BoardDetailUiState } sealed interface BoardPostApiUiState { - object Success : BoardPostApiUiState - object HttpError : BoardPostApiUiState - object NetworkError : BoardPostApiUiState - object Error : BoardPostApiUiState - object Loading : BoardPostApiUiState + data object Success : BoardPostApiUiState + data object HttpError : BoardPostApiUiState + data object NetworkError : BoardPostApiUiState + data object Error : BoardPostApiUiState + data object Loading : BoardPostApiUiState } sealed interface PatchLikeFavoriteUiState { @@ -52,8 +52,8 @@ sealed interface PatchLikeFavoriteUiState { val isFavorite: Boolean ) : PatchLikeFavoriteUiState - object HttpError : PatchLikeFavoriteUiState - object NetworkError : PatchLikeFavoriteUiState - object Error : PatchLikeFavoriteUiState - object Loading : PatchLikeFavoriteUiState + data object HttpError : PatchLikeFavoriteUiState + data object NetworkError : PatchLikeFavoriteUiState + data object Error : PatchLikeFavoriteUiState + data object Loading : PatchLikeFavoriteUiState } \ No newline at end of file diff --git a/frontend/app/src/main/java/com/example/haengsha/model/uiState/home/HomeApiUiState.kt b/frontend/app/src/main/java/com/example/haengsha/model/uiState/home/HomeApiUiState.kt index f233daf..576d3bd 100644 --- a/frontend/app/src/main/java/com/example/haengsha/model/uiState/home/HomeApiUiState.kt +++ b/frontend/app/src/main/java/com/example/haengsha/model/uiState/home/HomeApiUiState.kt @@ -1,9 +1,9 @@ package com.example.haengsha.model.uiState.home sealed interface HomeApiUiState { - object Success : HomeApiUiState - object HttpError : HomeApiUiState - object NetworkError : HomeApiUiState - object Error : HomeApiUiState - object Loading : HomeApiUiState + data object Success : HomeApiUiState + data object HttpError : HomeApiUiState + data object NetworkError : HomeApiUiState + data object Error : HomeApiUiState + data object Loading : HomeApiUiState } \ No newline at end of file diff --git a/frontend/app/src/main/java/com/example/haengsha/model/uiState/home/RecommendationApiUiState.kt b/frontend/app/src/main/java/com/example/haengsha/model/uiState/home/RecommendationApiUiState.kt index b05ab60..c28f879 100644 --- a/frontend/app/src/main/java/com/example/haengsha/model/uiState/home/RecommendationApiUiState.kt +++ b/frontend/app/src/main/java/com/example/haengsha/model/uiState/home/RecommendationApiUiState.kt @@ -7,8 +7,8 @@ sealed interface RecommendationApiUiState { val recommendationList: List ) : RecommendationApiUiState - object HttpError : RecommendationApiUiState - object NetworkError : RecommendationApiUiState - object Error : RecommendationApiUiState - object Loading : RecommendationApiUiState + data object HttpError : RecommendationApiUiState + data object NetworkError : RecommendationApiUiState + data object Error : RecommendationApiUiState + data object Loading : RecommendationApiUiState } \ No newline at end of file From 2a07029b2de4033ae3609e9d0890aa65bae08fad Mon Sep 17 00:00:00 2001 From: Seongjun Jo Date: Tue, 5 Dec 2023 15:38:32 +0900 Subject: [PATCH 05/12] refactor: HomeApiViewModel * remove dependency forward HomeViewModel --- .../model/uiState/home/HomeApiUiState.kt | 8 +++- .../model/viewModel/home/HomeApiViewModel.kt | 39 ++++--------------- .../com/example/haengsha/ui/HaengshaApp.kt | 3 +- .../example/haengsha/ui/screens/home/Home.kt | 14 +++++-- 4 files changed, 27 insertions(+), 37 deletions(-) diff --git a/frontend/app/src/main/java/com/example/haengsha/model/uiState/home/HomeApiUiState.kt b/frontend/app/src/main/java/com/example/haengsha/model/uiState/home/HomeApiUiState.kt index 576d3bd..bcfdebf 100644 --- a/frontend/app/src/main/java/com/example/haengsha/model/uiState/home/HomeApiUiState.kt +++ b/frontend/app/src/main/java/com/example/haengsha/model/uiState/home/HomeApiUiState.kt @@ -1,7 +1,13 @@ package com.example.haengsha.model.uiState.home +import com.example.haengsha.model.network.dataModel.EventResponse + sealed interface HomeApiUiState { - data object Success : HomeApiUiState + data class Success( + val festivalResponse: List?, + val academicResponse: List? + ) : HomeApiUiState + data object HttpError : HomeApiUiState data object NetworkError : HomeApiUiState data object Error : HomeApiUiState diff --git a/frontend/app/src/main/java/com/example/haengsha/model/viewModel/home/HomeApiViewModel.kt b/frontend/app/src/main/java/com/example/haengsha/model/viewModel/home/HomeApiViewModel.kt index 6939709..4426ccd 100644 --- a/frontend/app/src/main/java/com/example/haengsha/model/viewModel/home/HomeApiViewModel.kt +++ b/frontend/app/src/main/java/com/example/haengsha/model/viewModel/home/HomeApiViewModel.kt @@ -5,6 +5,7 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory.Companion.APPLICATION_KEY import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewmodel.initializer import androidx.lifecycle.viewmodel.viewModelFactory @@ -13,17 +14,12 @@ import com.example.haengsha.model.dataSource.HomeDataRepository import com.example.haengsha.model.network.dataModel.EventResponse import com.example.haengsha.model.uiState.home.HomeApiUiState import com.example.haengsha.model.uiState.home.RecommendationApiUiState -import com.example.haengsha.ui.screens.home.EventCardData -import com.example.haengsha.ui.screens.home.toEventCardData import kotlinx.coroutines.launch import retrofit2.HttpException import java.io.IOException import java.time.LocalDate -class HomeApiViewModel( - private val homeDataRepository: HomeDataRepository, - private val homeViewModel: HomeViewModel -) : ViewModel() { +class HomeApiViewModel(private val homeDataRepository: HomeDataRepository) : ViewModel() { var homeApiUiState: HomeApiUiState by mutableStateOf(HomeApiUiState.Loading) private set @@ -33,17 +29,11 @@ class HomeApiViewModel( private set companion object { - private lateinit var homeViewModelInstance: HomeViewModel - - fun Factory(homeViewModel: HomeViewModel): ViewModelProvider.Factory { - homeViewModelInstance = homeViewModel - return viewModelFactory { - initializer { - val application = - this[ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY] as HaengshaApplication - val homeDataRepository = application.container.homeDataRepository - HomeApiViewModel(homeDataRepository, homeViewModel) - } + val Factory: ViewModelProvider.Factory = viewModelFactory { + initializer { + val application = this[APPLICATION_KEY] as HaengshaApplication + val homeDataRepository = application.container.homeDataRepository + HomeApiViewModel(homeDataRepository) } } } @@ -55,23 +45,10 @@ class HomeApiViewModel( homeApiUiState = try { val festivalResponse: List? = homeDataRepository.getEventByDate(1, date.toString()) - val academicResponse: List? = homeDataRepository.getEventByDate(0, date.toString()) - - val academicCardDataList: List? = - academicResponse?.map { it.toEventCardData() } - - val festivalCardDataList: List? = - festivalResponse?.map { it.toEventCardData() } - - homeViewModel.updateEventItems(festivalCardDataList, academicCardDataList) - homeViewModel.updateSelectedDate(date) - - HomeApiUiState.Success + HomeApiUiState.Success(festivalResponse, academicResponse) } catch (e: HttpException) { - homeViewModel.updateEventItems(listOf(), listOf()) - homeViewModel.updateSelectedDate(date) HomeApiUiState.HttpError } catch (e: IOException) { HomeApiUiState.NetworkError diff --git a/frontend/app/src/main/java/com/example/haengsha/ui/HaengshaApp.kt b/frontend/app/src/main/java/com/example/haengsha/ui/HaengshaApp.kt index 6537ad3..4d58ec3 100644 --- a/frontend/app/src/main/java/com/example/haengsha/ui/HaengshaApp.kt +++ b/frontend/app/src/main/java/com/example/haengsha/ui/HaengshaApp.kt @@ -45,8 +45,7 @@ fun HaengshaApp(mainNavController: NavHostController = rememberNavController()) val navigationViewModel: NavigationViewModel = viewModel() val navigationUiState by navigationViewModel.uiState.collectAsState() val homeViewModel: HomeViewModel = viewModel() - val homeApiViewModel: HomeApiViewModel = - viewModel(factory = HomeApiViewModel.Factory(homeViewModel)) + val homeApiViewModel: HomeApiViewModel = viewModel(factory = HomeApiViewModel.Factory) val backStackEntry = mainNavController.currentBackStackEntryAsState() val currentScreenName = navigationUiState.screen diff --git a/frontend/app/src/main/java/com/example/haengsha/ui/screens/home/Home.kt b/frontend/app/src/main/java/com/example/haengsha/ui/screens/home/Home.kt index 29304c7..6776d73 100644 --- a/frontend/app/src/main/java/com/example/haengsha/ui/screens/home/Home.kt +++ b/frontend/app/src/main/java/com/example/haengsha/ui/screens/home/Home.kt @@ -173,6 +173,14 @@ fun HomeScreen( when (homeApiUiState) { is HomeApiUiState.Success -> { + val academicCardDataList: List? = + homeApiUiState.academicResponse?.map { it.toEventCardData() } + + val festivalCardDataList: List? = + homeApiUiState.festivalResponse?.map { it.toEventCardData() } + + homeViewModel.updateEventItems(festivalCardDataList, academicCardDataList) + homeViewModel.updateSelectedDate(selection) TabView(homeViewModel, homeApiViewModel, userUiState) } @@ -201,7 +209,7 @@ fun HomeScreen( verticalArrangement = Arrangement.Center, ) { Text( - text = "이벤트를 불러오는 중 문제가 발생했어요!\n\n다시 시도해주세요.", + text = "이벤트를 불러오는 중 문제가 발생했어요.\n\n다시 시도해주세요.", fontFamily = poppins, fontSize = 18.sp, fontWeight = FontWeight.SemiBold, @@ -233,7 +241,7 @@ fun HomeScreen( verticalArrangement = Arrangement.Center, ) { Text( - text = "알 수 없는 문제가 발생했어요!\n\n메일로 문의해주세요.", + text = "알 수 없는 문제가 발생했어요.\n\n메일로 문의해주세요.", fontFamily = poppins, fontSize = 18.sp, fontWeight = FontWeight.SemiBold, @@ -389,7 +397,7 @@ fun stringToDate(dateString: String): LocalDate { fun HomeScreenPreview() { val homeViewModel = viewModel() val homeApiViewModel: HomeApiViewModel = - viewModel(factory = HomeApiViewModel.Factory(homeViewModel)) + viewModel(factory = HomeApiViewModel.Factory) Home( homeViewModel = homeViewModel, From 39d91b5b82adbef8e38774dbc6cc89382b7d594c Mon Sep 17 00:00:00 2001 From: Seongjun Jo Date: Tue, 5 Dec 2023 20:50:27 +0900 Subject: [PATCH 06/12] refactor: remove redundant code * remove uselessly defined variable in HomeViewModel --- .../model/viewModel/home/HomeViewModel.kt | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/frontend/app/src/main/java/com/example/haengsha/model/viewModel/home/HomeViewModel.kt b/frontend/app/src/main/java/com/example/haengsha/model/viewModel/home/HomeViewModel.kt index 9b98635..2b38ed9 100644 --- a/frontend/app/src/main/java/com/example/haengsha/model/viewModel/home/HomeViewModel.kt +++ b/frontend/app/src/main/java/com/example/haengsha/model/viewModel/home/HomeViewModel.kt @@ -6,18 +6,19 @@ import com.example.haengsha.ui.screens.home.EventCardData import java.time.LocalDate class HomeViewModel : ViewModel() { - private val _selectedDate = MutableLiveData(LocalDate.now()) - private val _festivalItems = MutableLiveData?>() - private val _academicItems = MutableLiveData?>() - val festivalItems: MutableLiveData?> = _festivalItems - val academicItems: MutableLiveData?> = _academicItems + private val selectedDate = MutableLiveData(LocalDate.now()) + val festivalItems = MutableLiveData?>() + val academicItems = MutableLiveData?>() fun updateSelectedDate(newDate: LocalDate) { - _selectedDate.value = newDate // Update functions to set LiveData properties + selectedDate.value = newDate // Update functions to set LiveData properties } - fun updateEventItems(festivalItems: List?, academicItems: List?) { - _festivalItems.value = festivalItems - _academicItems.value = academicItems + fun updateEventItems( + newFestivalItems: List?, + newAcademicItems: List? + ) { + festivalItems.value = newFestivalItems + academicItems.value = newAcademicItems } } From ae7bc4f66047278de2d8856ad11b2f753acd2f3d Mon Sep 17 00:00:00 2001 From: Songmin17 Date: Wed, 6 Dec 2023 13:08:51 +0900 Subject: [PATCH 07/12] backend fix: unique posts in recommendations --- backend/post/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/post/views.py b/backend/post/views.py index d085cb8..b20a485 100644 --- a/backend/post/views.py +++ b/backend/post/views.py @@ -207,7 +207,7 @@ class PostRecommendView(APIView): def get(self, request): user = request.user today = date.today() - posts = Post.objects.filter(recommend_users=user,event_durations__event_day__gte=today).order_by("-recommend__score") + posts = Post.objects.filter(recommend_users=user,event_durations__event_day__gte=today).order_by("-recommend__score").distinct() # scores = Recommend.objects.filter(user=request.user).values('score') serializer = PostRecommendSerializer(posts, many=True, context={'request': request}) return Response(serializer.data, status=200) From 29c720d91399ccbb513623576bbdda15c3f525ed Mon Sep 17 00:00:00 2001 From: Songmin17 Date: Wed, 6 Dec 2023 13:09:32 +0900 Subject: [PATCH 08/12] frontend fix: in search view, handle non-String inputs --- .../haengsha/model/dataSource/BoardDataRepository.kt | 2 +- .../example/haengsha/model/network/dataModel/BoardData.kt | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/frontend/app/src/main/java/com/example/haengsha/model/dataSource/BoardDataRepository.kt b/frontend/app/src/main/java/com/example/haengsha/model/dataSource/BoardDataRepository.kt index d555287..10bd8e5 100644 --- a/frontend/app/src/main/java/com/example/haengsha/model/dataSource/BoardDataRepository.kt +++ b/frontend/app/src/main/java/com/example/haengsha/model/dataSource/BoardDataRepository.kt @@ -57,7 +57,7 @@ class NetworkBoardDataRepository( override suspend fun searchEvent(searchRequest: SearchRequest): List { return boardApiService.searchEvent( searchRequest.token, - searchRequest.keyword, + searchRequest.keywordAsString, searchRequest.isFestival, searchRequest.startDate, searchRequest.endDate diff --git a/frontend/app/src/main/java/com/example/haengsha/model/network/dataModel/BoardData.kt b/frontend/app/src/main/java/com/example/haengsha/model/network/dataModel/BoardData.kt index 058f3d1..add3afe 100644 --- a/frontend/app/src/main/java/com/example/haengsha/model/network/dataModel/BoardData.kt +++ b/frontend/app/src/main/java/com/example/haengsha/model/network/dataModel/BoardData.kt @@ -102,8 +102,12 @@ data class BoardPostResponse( data class SearchRequest( val token: String, - val keyword: String, + var keyword: Any, val isFestival: Int, val startDate: String, val endDate: String -) \ No newline at end of file +) { + // Custom getter for keyword that always returns a String + val keywordAsString: String + get() = keyword.toString() +} \ No newline at end of file From 49d65a4f75f4763e8371c25e8962ef68ab7c4f74 Mon Sep 17 00:00:00 2001 From: Songmin17 Date: Wed, 6 Dec 2023 13:46:30 +0900 Subject: [PATCH 09/12] Revert "frontend fix: in search view, handle non-String inputs" This reverts commit 29c720d91399ccbb513623576bbdda15c3f525ed. --- .../haengsha/model/dataSource/BoardDataRepository.kt | 2 +- .../example/haengsha/model/network/dataModel/BoardData.kt | 8 ++------ 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/frontend/app/src/main/java/com/example/haengsha/model/dataSource/BoardDataRepository.kt b/frontend/app/src/main/java/com/example/haengsha/model/dataSource/BoardDataRepository.kt index 10bd8e5..d555287 100644 --- a/frontend/app/src/main/java/com/example/haengsha/model/dataSource/BoardDataRepository.kt +++ b/frontend/app/src/main/java/com/example/haengsha/model/dataSource/BoardDataRepository.kt @@ -57,7 +57,7 @@ class NetworkBoardDataRepository( override suspend fun searchEvent(searchRequest: SearchRequest): List { return boardApiService.searchEvent( searchRequest.token, - searchRequest.keywordAsString, + searchRequest.keyword, searchRequest.isFestival, searchRequest.startDate, searchRequest.endDate diff --git a/frontend/app/src/main/java/com/example/haengsha/model/network/dataModel/BoardData.kt b/frontend/app/src/main/java/com/example/haengsha/model/network/dataModel/BoardData.kt index add3afe..058f3d1 100644 --- a/frontend/app/src/main/java/com/example/haengsha/model/network/dataModel/BoardData.kt +++ b/frontend/app/src/main/java/com/example/haengsha/model/network/dataModel/BoardData.kt @@ -102,12 +102,8 @@ data class BoardPostResponse( data class SearchRequest( val token: String, - var keyword: Any, + val keyword: String, val isFestival: Int, val startDate: String, val endDate: String -) { - // Custom getter for keyword that always returns a String - val keywordAsString: String - get() = keyword.toString() -} \ No newline at end of file +) \ No newline at end of file From 0c8432c3e1c8ff748ff49a4bfad720bbfeb77bf7 Mon Sep 17 00:00:00 2001 From: Seongjun Jo Date: Wed, 6 Dec 2023 18:40:32 +0900 Subject: [PATCH 10/12] fix: regex for password set * add regex check for password set --- .../screens/login/findPassword/PasswordResetScreen.kt | 11 ++++++++++- .../screens/login/signup/SignupPasswordSetScreen.kt | 11 ++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/frontend/app/src/main/java/com/example/haengsha/ui/screens/login/findPassword/PasswordResetScreen.kt b/frontend/app/src/main/java/com/example/haengsha/ui/screens/login/findPassword/PasswordResetScreen.kt index 84c496c..bffe135 100644 --- a/frontend/app/src/main/java/com/example/haengsha/ui/screens/login/findPassword/PasswordResetScreen.kt +++ b/frontend/app/src/main/java/com/example/haengsha/ui/screens/login/findPassword/PasswordResetScreen.kt @@ -58,6 +58,7 @@ fun PasswordResetScreen( var isPasswordError by remember { mutableStateOf(false) } var isPasswordCheckError by remember { mutableStateOf(false) } var isPasswordReset by remember { mutableStateOf(false) } + val pattern = "^(?=.*[a-zA-Z])(?=.*\\d)[a-zA-Z\\d]{4,10}$".toRegex() val focusManager = LocalFocusManager.current val keyboardController = LocalSoftwareKeyboardController.current @@ -130,11 +131,19 @@ fun PasswordResetScreen( Toast.LENGTH_SHORT, true ).show() + } else if (!pattern.matches(passwordInput)) { + isPasswordError = true + Toasty.error( + loginContext, + "비밀번호 형식을 지켜주세요", + Toast.LENGTH_SHORT, + true + ).show() } else if (passwordCheckInput != passwordInput) { isPasswordCheckError = true Toasty.error( loginContext, - "비밀번호를 확인해주세요", + "비밀번호가 서로 달라요", Toast.LENGTH_SHORT, true ).show() diff --git a/frontend/app/src/main/java/com/example/haengsha/ui/screens/login/signup/SignupPasswordSetScreen.kt b/frontend/app/src/main/java/com/example/haengsha/ui/screens/login/signup/SignupPasswordSetScreen.kt index f89bd9c..238bdca 100644 --- a/frontend/app/src/main/java/com/example/haengsha/ui/screens/login/signup/SignupPasswordSetScreen.kt +++ b/frontend/app/src/main/java/com/example/haengsha/ui/screens/login/signup/SignupPasswordSetScreen.kt @@ -48,6 +48,7 @@ fun SignupPasswordSetScreen( var passwordCheckInput: String by remember { mutableStateOf("") } var isPasswordError by remember { mutableStateOf(false) } var isPasswordCheckError by remember { mutableStateOf(false) } + val pattern = "^(?=.*[a-zA-Z])(?=.*\\d)[a-zA-Z\\d]{4,10}$".toRegex() val focusManager = LocalFocusManager.current val keyboardController = LocalSoftwareKeyboardController.current @@ -115,12 +116,20 @@ fun SignupPasswordSetScreen( Toast.LENGTH_SHORT, true ).show() + } else if (!pattern.matches(passwordInput)) { + isPasswordError = true + Toasty.error( + loginContext, + "비밀번호 형식을 지켜주세요", + Toast.LENGTH_SHORT, + true + ).show() } else { if (passwordCheckInput != passwordInput) { isPasswordCheckError = true Toasty.error( loginContext, - "비밀번호를 확인해주세요", + "비밀번호가 서로 달라요", Toast.LENGTH_SHORT, true ).show() From 2297e923e77c6f4cfa555bf6a7662a6e16ca04b6 Mon Sep 17 00:00:00 2001 From: Seongjun Jo Date: Wed, 6 Dec 2023 18:44:50 +0900 Subject: [PATCH 11/12] fix: restriction of post * allow special character in place and time for posting --- .../example/haengsha/ui/screens/board/BoardPostScreen.kt | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/frontend/app/src/main/java/com/example/haengsha/ui/screens/board/BoardPostScreen.kt b/frontend/app/src/main/java/com/example/haengsha/ui/screens/board/BoardPostScreen.kt index 35f2201..f0cbc93 100644 --- a/frontend/app/src/main/java/com/example/haengsha/ui/screens/board/BoardPostScreen.kt +++ b/frontend/app/src/main/java/com/example/haengsha/ui/screens/board/BoardPostScreen.kt @@ -648,7 +648,6 @@ private fun checkPostFormat( eventTime: String, eventContent: String ): String { - val noSpecialCharacterRegex = "^[a-zA-Zㄱ-ㅎㅏ-ㅣ가-힣\\d\\s]+$".toRegex() val possibleRegexPattern = "^[0-9a-zA-Zㄱ-ㅎㅏ-ㅣ가-힣+×÷=/_<>\\[\\]!@#\$%^&*()\\-'\":;?`~\\\\|{}€£¥₩♤♡◇♧☆▪︎¤《》¡¿°•○●□■.,‽±』」〕】『「〔【№₽٪‰‐—–♠♥◆♣★\\s\\n]+$".toRegex() @@ -680,16 +679,16 @@ private fun checkPostFormat( return "장소의 앞뒤 공백을 제거해주세요." } else if (eventPlace.length !in 2..20) { return "장소는 2자 이상 20자 이하로 입력해주세요." - } else if (!noSpecialCharacterRegex.matches(eventPlace)) { - return "장소는 한글, 영어, 숫자로만 입력해주세요." + } else if (!possibleRegexPattern.matches(eventPlace)) { + return "장소는 한글, 영어, 숫자, 특수문자로만 입력해주세요." } if (eventTime.startsWith(" ") || eventTime.endsWith(" ")) { return "시간의 앞뒤 공백을 제거해주세요." } else if (eventTime.length !in 2..20) { return "시간은 2자 이상 20자 이하로 입력해주세요." - } else if (!noSpecialCharacterRegex.matches(eventTime)) { - return "시간은 한글, 영어, 숫자로만 입력해주세요." + } else if (!possibleRegexPattern.matches(eventTime)) { + return "시간은 한글, 영어, 숫자, 특수문자로만 입력해주세요." } if (eventContent.trim().isEmpty()) { From 9000ce67f0517bae619a6176421bab35f54b7493 Mon Sep 17 00:00:00 2001 From: Seongjun Jo Date: Wed, 6 Dec 2023 20:23:44 +0900 Subject: [PATCH 12/12] fix: network error toast * add additional ui state & function * prevent redundant toast call --- .../model/uiState/board/BoardApiUiState.kt | 1 + .../viewModel/board/BoardApiViewModel.kt | 6 ++- .../com/example/haengsha/ui/HaengshaApp.kt | 2 +- .../haengsha/ui/screens/board/BoardScreen.kt | 50 ++++++++----------- 4 files changed, 27 insertions(+), 32 deletions(-) diff --git a/frontend/app/src/main/java/com/example/haengsha/model/uiState/board/BoardApiUiState.kt b/frontend/app/src/main/java/com/example/haengsha/model/uiState/board/BoardApiUiState.kt index b283c10..b09097b 100644 --- a/frontend/app/src/main/java/com/example/haengsha/model/uiState/board/BoardApiUiState.kt +++ b/frontend/app/src/main/java/com/example/haengsha/model/uiState/board/BoardApiUiState.kt @@ -12,6 +12,7 @@ sealed interface BoardListUiState { data object NetworkError : BoardListUiState data object Error : BoardListUiState data object Loading : BoardListUiState + data object Default : BoardListUiState } sealed interface BoardFavoriteUiState { diff --git a/frontend/app/src/main/java/com/example/haengsha/model/viewModel/board/BoardApiViewModel.kt b/frontend/app/src/main/java/com/example/haengsha/model/viewModel/board/BoardApiViewModel.kt index bf0789b..5b8ff3b 100644 --- a/frontend/app/src/main/java/com/example/haengsha/model/viewModel/board/BoardApiViewModel.kt +++ b/frontend/app/src/main/java/com/example/haengsha/model/viewModel/board/BoardApiViewModel.kt @@ -164,10 +164,14 @@ class BoardApiViewModel(private val boardDataRepository: BoardDataRepository) : patchLikeFavoriteUiState = PatchLikeFavoriteUiState.Loading } - fun resetBoardListUiState() { + fun resetBoardListUiStateToLoading() { boardListUiState = BoardListUiState.Loading } + fun resetBoardListUiStateToDefault() { + boardListUiState = BoardListUiState.Default + } + fun resetBoardPostApiUiState() { boardPostApiUiState = BoardPostApiUiState.Loading } diff --git a/frontend/app/src/main/java/com/example/haengsha/ui/HaengshaApp.kt b/frontend/app/src/main/java/com/example/haengsha/ui/HaengshaApp.kt index 4d58ec3..36b1a26 100644 --- a/frontend/app/src/main/java/com/example/haengsha/ui/HaengshaApp.kt +++ b/frontend/app/src/main/java/com/example/haengsha/ui/HaengshaApp.kt @@ -365,7 +365,7 @@ fun HaengshaApp(mainNavController: NavHostController = rememberNavController()) userViewModel.resetUserData() loginApiViewModel.resetLoginApiUiState() boardViewModel.resetBoardUiState() - boardApiViewModel.resetBoardListUiState() + boardApiViewModel.resetBoardListUiStateToLoading() mainNavController.navigate(MainRoute.Login.route) { popUpTo(mainNavController.graph.id) { inclusive = true } } diff --git a/frontend/app/src/main/java/com/example/haengsha/ui/screens/board/BoardScreen.kt b/frontend/app/src/main/java/com/example/haengsha/ui/screens/board/BoardScreen.kt index 2c66b80..c84b9cd 100644 --- a/frontend/app/src/main/java/com/example/haengsha/ui/screens/board/BoardScreen.kt +++ b/frontend/app/src/main/java/com/example/haengsha/ui/screens/board/BoardScreen.kt @@ -163,46 +163,36 @@ fun BoardScreen( ) { when (boardListUiState) { is BoardListUiState.HttpError -> { - Box( - modifier = Modifier - .fillMaxSize() - .padding(innerPadding), - contentAlignment = Alignment.Center - ) { - Text( - text = "찾는 행사가 없어요 :(", - fontFamily = poppins, - fontSize = 30.sp, - fontWeight = FontWeight.SemiBold, - textAlign = TextAlign.Center - ) - } + Toasty.error( + boardContext, + "행사 검색에 문제가 발생했어요!\n다시 시도해주세요", + Toasty.LENGTH_SHORT + ) + .show() + boardApiViewModel.resetBoardListUiStateToDefault() } is BoardListUiState.NetworkError -> { - Box( - modifier = Modifier - .fillMaxSize() - .padding(innerPadding) - ) { - Toasty.error(boardContext, "네트워크 연결을 확인해주세요", Toasty.LENGTH_SHORT) - .show() - } + Toasty.error(boardContext, "네트워크 연결을 확인해주세요", Toasty.LENGTH_SHORT) + .show() + boardApiViewModel.resetBoardListUiStateToDefault() } is BoardListUiState.Error -> { + Toasty.error( + boardContext, + "알 수 없는 에러가 발생했어요 :( 메일로 제보해주세요!", + Toasty.LENGTH_SHORT + ).show() + boardApiViewModel.resetBoardListUiStateToDefault() + } + + is BoardListUiState.Default -> { Box( modifier = Modifier .fillMaxSize() .padding(innerPadding) - ) { - Toasty.error( - boardContext, - "알 수 없는 에러가 발생했어요 :( 메일로 제보해주세요!", - Toasty.LENGTH_SHORT - ).show() - } - + ) } is BoardListUiState.Loading -> {