diff --git a/frontend/app/build.gradle.kts b/frontend/app/build.gradle.kts index 8a452eb..5e97777 100644 --- a/frontend/app/build.gradle.kts +++ b/frontend/app/build.gradle.kts @@ -23,12 +23,16 @@ android { buildTypes { release { + isDebuggable = false isMinifyEnabled = false proguardFiles( getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" ) } + debug { + isDebuggable = true + } } compileOptions { sourceCompatibility = JavaVersion.VERSION_1_8 diff --git a/frontend/app/src/androidTest/java/com/example/haengsha/instrumentedTest/uiTest/HomeScreenUITest.kt b/frontend/app/src/androidTest/java/com/example/haengsha/instrumentedTest/uiTest/HomeScreenUITest.kt index 167a232..12daaef 100644 --- a/frontend/app/src/androidTest/java/com/example/haengsha/instrumentedTest/uiTest/HomeScreenUITest.kt +++ b/frontend/app/src/androidTest/java/com/example/haengsha/instrumentedTest/uiTest/HomeScreenUITest.kt @@ -101,9 +101,9 @@ class HomeScreenUITest { personalUser_loginToHomeScreen() composeTestRule.onNodeWithContentDescription("calendar icon") .performClick() - composeTestRule.onNodeWithText("OK") + composeTestRule.onNodeWithText("확인") .performClick() - composeTestRule.onNodeWithText("OK") + composeTestRule.onNodeWithText("확인") .assertIsNotDisplayed() } @@ -114,7 +114,7 @@ class HomeScreenUITest { .performClick() composeTestRule.onNodeWithText("Sunday, December 10, 2023") .performClick() - composeTestRule.onNodeWithText("OK") + composeTestRule.onNodeWithText("확인") .performClick() composeTestRule.onNodeWithText("행사 불러오는 중...") .isDisplayed() @@ -127,7 +127,7 @@ class HomeScreenUITest { .performClick() composeTestRule.onNodeWithText("Sunday, December 10, 2023") .performClick() - composeTestRule.onNodeWithText("OK") + composeTestRule.onNodeWithText("확인") .performClick() composeTestRule.waitUntil(5000) { composeTestRule.onNodeWithText("SNUPO SNUp\nSNUPO & SNUpia 하계 앙상블") @@ -144,7 +144,7 @@ class HomeScreenUITest { .performClick() composeTestRule.onNodeWithText("Sunday, December 10, 2023") .performClick() - composeTestRule.onNodeWithText("OK") + composeTestRule.onNodeWithText("확인") .performClick() composeTestRule.waitUntil(5000) { composeTestRule.onNodeWithText("행사 추천 받기") @@ -167,7 +167,7 @@ class HomeScreenUITest { .performClick() composeTestRule.onNodeWithText("Friday, December 1, 2023") .performClick() - composeTestRule.onNodeWithText("OK") + composeTestRule.onNodeWithText("확인") .performClick() composeTestRule.waitUntil(5000) { composeTestRule.onNodeWithText("오늘은 예정된 축제가 없어요!") @@ -184,7 +184,7 @@ class HomeScreenUITest { .performClick() composeTestRule.onNodeWithText("Friday, December 1, 2023") .performClick() - composeTestRule.onNodeWithText("OK") + composeTestRule.onNodeWithText("확인") .performClick() composeTestRule.waitUntil(5000) { composeTestRule.onNodeWithText("행사 불러오는 중...") diff --git a/frontend/app/src/main/java/com/example/haengsha/model/dataSource/EventCardData.kt b/frontend/app/src/main/java/com/example/haengsha/model/dataSource/EventCardData.kt new file mode 100644 index 0000000..4c4289c --- /dev/null +++ b/frontend/app/src/main/java/com/example/haengsha/model/dataSource/EventCardData.kt @@ -0,0 +1,22 @@ +package com.example.haengsha.model.dataSource + +import java.time.LocalDate + +data class EventCardData( + val id: Int, + val organizer: String, + val eventTitle: String, + val startDate: LocalDate, + val endDate: LocalDate, + val likes: Int, + val favorites: Int, + val eventType: String, + val place: String = "", + val time: String = "", + val image: String = "" +) + +data class TabItem( + val title: String, + val eventCards: List +) \ No newline at end of file diff --git a/frontend/app/src/main/java/com/example/haengsha/model/dataSource/SampleImage.kt b/frontend/app/src/main/java/com/example/haengsha/model/dataSource/SampleImage.kt new file mode 100644 index 0000000..129ca20 --- /dev/null +++ b/frontend/app/src/main/java/com/example/haengsha/model/dataSource/SampleImage.kt @@ -0,0 +1,27 @@ +package com.example.haengsha.model.dataSource + +import com.example.haengsha.R + +enum class SampleImage(val id: Int) { + ImageFestival1(R.drawable.f_alchole), + ImageFestival2(R.drawable.f_animu), + ImageFestival3(R.drawable.f_cinema), + ImageFestival4(R.drawable.f_cushion), + ImageFestival5(R.drawable.f_dongsojae), + ImageFestival6(R.drawable.f_goahead), + ImageFestival7(R.drawable.f_meeting), + ImageFestival8(R.drawable.f_pub), + ImageFestival9(R.drawable.f_recruite), + ImageFestival10(R.drawable.f_taco), + ImageAcademic1(R.drawable.a_aiseminar), + ImageAcademic2(R.drawable.a_artspace), + ImageAcademic3(R.drawable.a_bookconcert), + ImageAcademic4(R.drawable.a_law), + ImageAcademic5(R.drawable.a_math), + ImageAcademic6(R.drawable.a_music), + ImageAcademic7(R.drawable.a_piano), + ImageAcademic8(R.drawable.a_social), + ImageAcademic9(R.drawable.a_writing), + ImageAcademic10(R.drawable.a_network), + ImageAcademicDefault(R.drawable.a_snu_enterance) +} \ No newline at end of file diff --git a/frontend/app/src/main/java/com/example/haengsha/model/route/HomeRoute.kt b/frontend/app/src/main/java/com/example/haengsha/model/route/HomeRoute.kt new file mode 100644 index 0000000..d23f1cd --- /dev/null +++ b/frontend/app/src/main/java/com/example/haengsha/model/route/HomeRoute.kt @@ -0,0 +1,6 @@ +package com.example.haengsha.model.route + +sealed class HomeRoute(val route: String) { + data object Home : HomeRoute("Home") + data object HomeDetail : HomeRoute("Details") +} \ No newline at end of file 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 f874295..3e818b7 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 @@ -10,6 +10,7 @@ import kotlinx.coroutines.flow.update class BoardViewModel : ViewModel() { private val _boardUiState = MutableStateFlow(BoardUiState()) val boardUiState = _boardUiState.asStateFlow() + private val _tempBoardUiState = MutableStateFlow(BoardUiState()) private val _boardPostUiState = MutableStateFlow(BoardPostUiState()) val boardPostUiState = _boardPostUiState.asStateFlow() @@ -79,13 +80,24 @@ class BoardViewModel : ViewModel() { updateSearchParameter(newEndDate, "endDate", "filter") } - fun updateFilterInitialState() { - updateSearchParameter("foo", "bar", "filter") + fun savePreviousFilter() { + _tempBoardUiState.value = _boardUiState.value } - fun resetFilterInitialState() { + fun cancelFilter() { + _boardUiState.value = _tempBoardUiState.value + } + + fun resetFilter() { _boardUiState.update { currentState -> - currentState.copy(initialState = true) + currentState.copy( + token = currentState.token, + keyword = currentState.keyword, + isFestival = 2, + startDate = "", + endDate = "", + initialState = currentState.initialState + ) } } @@ -120,7 +132,7 @@ class BoardViewModel : ViewModel() { isFestival = if (type == "isFestival") newParameter.toInt() else currentState.isFestival, startDate = if (type == "startDate") newParameter else currentState.startDate, endDate = if (type == "endDate") newParameter else currentState.endDate, - initialState = false + initialState = if (type == "keyword") false else currentState.initialState ) } } 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 2b38ed9..cb482fd 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 @@ -2,16 +2,25 @@ package com.example.haengsha.model.viewModel.home import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel -import com.example.haengsha.ui.screens.home.EventCardData +import com.example.haengsha.model.dataSource.EventCardData +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow import java.time.LocalDate class HomeViewModel : ViewModel() { - private val selectedDate = MutableLiveData(LocalDate.now()) + private val _selectedDate = MutableStateFlow(LocalDate.now()) + val selectedDate = _selectedDate.asStateFlow() + var initialEnter = true + var selectionChanged = false + var initialRecommendationState = true val festivalItems = MutableLiveData?>() val academicItems = MutableLiveData?>() fun updateSelectedDate(newDate: LocalDate) { - selectedDate.value = newDate // Update functions to set LiveData properties + if (_selectedDate.value != newDate) { + _selectedDate.value = newDate + selectionChanged = true + } } fun updateEventItems( 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 36b1a26..75f9df5 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 @@ -76,6 +76,12 @@ fun HaengshaApp(mainNavController: NavHostController = rememberNavController()) } } } + } else if (currentScreenType == "Home") { + mainNavController.navigate(MainRoute.Home.route) { + if (backStackEntry.value?.destination?.route == "Home") { + mainNavController.popBackStack() + } + } } else { mainNavController.navigate(MainRoute.Favorite.route) { if (backStackEntry.value?.destination?.route == "Favorite") { @@ -192,6 +198,9 @@ fun HaengshaApp(mainNavController: NavHostController = rememberNavController()) Home( homeViewModel = homeViewModel, homeApiViewModel = homeApiViewModel, + boardApiViewModel = boardApiViewModel, + boardViewModel = boardViewModel, + navigationViewModel = navigationViewModel, innerPadding = innerPadding, userUiState = userUiState, ) @@ -364,6 +373,9 @@ fun HaengshaApp(mainNavController: NavHostController = rememberNavController()) is LoginApiUiState.Success -> { userViewModel.resetUserData() loginApiViewModel.resetLoginApiUiState() + homeViewModel.initialEnter = true + homeViewModel.selectionChanged = false + homeViewModel.initialRecommendationState = true boardViewModel.resetBoardUiState() boardApiViewModel.resetBoardListUiStateToLoading() mainNavController.navigate(MainRoute.Login.route) { 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 39ae1d8..921871f 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 @@ -75,10 +75,10 @@ import com.example.haengsha.ui.theme.ButtonBlue import com.example.haengsha.ui.theme.HaengshaBlue import com.example.haengsha.ui.theme.PlaceholderGrey import com.example.haengsha.ui.theme.poppins +import com.example.haengsha.ui.uiComponents.BoardDatePickerDialog import com.example.haengsha.ui.uiComponents.CheckBox import com.example.haengsha.ui.uiComponents.ConfirmDialog import com.example.haengsha.ui.uiComponents.CustomCircularProgressIndicator -import com.example.haengsha.ui.uiComponents.CustomDatePickerDialog import com.example.haengsha.ui.uiComponents.CustomHorizontalDivider import com.example.haengsha.ui.uiComponents.CustomVerticalDivider import com.example.haengsha.ui.uiComponents.customLargeTextField @@ -575,7 +575,7 @@ fun BoardPostScreen( } if (startDatePick) { - CustomDatePickerDialog( + BoardDatePickerDialog( onDismissRequest = { startDatePick = false }, boardViewModel = boardViewModel, type = "startDate", @@ -584,7 +584,7 @@ fun BoardPostScreen( } if (endDatePick) { - CustomDatePickerDialog( + BoardDatePickerDialog( onDismissRequest = { endDatePick = false }, boardViewModel = boardViewModel, type = "endDate", 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 b890b56..2daf1e3 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 @@ -56,12 +56,12 @@ import com.example.haengsha.ui.theme.ButtonBlue import com.example.haengsha.ui.theme.HaengshaBlue import com.example.haengsha.ui.theme.PlaceholderGrey import com.example.haengsha.ui.theme.poppins +import com.example.haengsha.ui.uiComponents.BoardDatePickerDialog import com.example.haengsha.ui.uiComponents.CustomCircularProgressIndicator -import com.example.haengsha.ui.uiComponents.CustomDatePickerDialog import com.example.haengsha.ui.uiComponents.CustomHorizontalDivider import com.example.haengsha.ui.uiComponents.FilterDialog import com.example.haengsha.ui.uiComponents.SearchBar -import com.example.haengsha.ui.uiComponents.listItem +import com.example.haengsha.ui.uiComponents.boardListItem import es.dmoral.toasty.Toasty @Composable @@ -141,6 +141,7 @@ fun BoardScreen( val filterText = if (filterDateText.isEmpty()) filterCategoryText else "$filterDateText, $filterCategoryText" Text( + modifier = Modifier.padding(top = 2.dp), text = "필터 : $filterText", fontFamily = poppins, fontSize = 12.sp, @@ -268,7 +269,7 @@ fun BoardScreen( boardViewModel.updateEventId(event.id) boardNavController.navigate(BoardRoute.BoardDetail.route) }) { - listItem( + boardListItem( isFavorite = false, event = event ) @@ -314,7 +315,7 @@ fun BoardScreen( } if (startDatePick) { - CustomDatePickerDialog( + BoardDatePickerDialog( onDismissRequest = { startDatePick = false }, boardViewModel = boardViewModel, type = "startDate", @@ -323,7 +324,7 @@ fun BoardScreen( } if (endDatePick) { - CustomDatePickerDialog( + BoardDatePickerDialog( onDismissRequest = { endDatePick = false }, boardViewModel = boardViewModel, type = "endDate", diff --git a/frontend/app/src/main/java/com/example/haengsha/ui/screens/favorite/FavoriteScreen.kt b/frontend/app/src/main/java/com/example/haengsha/ui/screens/favorite/FavoriteScreen.kt index e709792..f2829ef 100644 --- a/frontend/app/src/main/java/com/example/haengsha/ui/screens/favorite/FavoriteScreen.kt +++ b/frontend/app/src/main/java/com/example/haengsha/ui/screens/favorite/FavoriteScreen.kt @@ -38,7 +38,7 @@ import com.example.haengsha.ui.theme.PlaceholderGrey import com.example.haengsha.ui.theme.poppins import com.example.haengsha.ui.uiComponents.CustomCircularProgressIndicator import com.example.haengsha.ui.uiComponents.CustomHorizontalDivider -import com.example.haengsha.ui.uiComponents.listItem +import com.example.haengsha.ui.uiComponents.boardListItem import es.dmoral.toasty.Toasty @Composable @@ -184,7 +184,7 @@ fun FavoriteScreen( boardViewModel.updateEventId(event.id) favoriteNavController.navigate(FavoriteRoute.FavoriteDetail.route) }) { - listItem( + boardListItem( isFavorite = true, event = event ) diff --git a/frontend/app/src/main/java/com/example/haengsha/ui/screens/home/EventCard.kt b/frontend/app/src/main/java/com/example/haengsha/ui/screens/home/EventCard.kt deleted file mode 100644 index 864f2b9..0000000 --- a/frontend/app/src/main/java/com/example/haengsha/ui/screens/home/EventCard.kt +++ /dev/null @@ -1,111 +0,0 @@ -package com.example.haengsha.ui.screens.home - -import androidx.compose.foundation.BorderStroke -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding -import androidx.compose.material3.CardDefaults -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.OutlinedCard -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.testTag -import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp -import com.example.haengsha.ui.theme.LikePink -import com.example.haengsha.ui.theme.md_theme_light_onSurfaceVariant -import com.example.haengsha.ui.theme.poppins -import java.time.LocalDate -import java.time.format.DateTimeFormatter - -fun formatDateToMMDD(date: LocalDate): String { - val formatter = DateTimeFormatter.ofPattern("MM-dd") - return date.format(formatter) -} - - -@Composable -fun EventCard( - organizer: String, - eventTitle: String, - startDate: LocalDate, - endDate: LocalDate, - likes: Int, -) { - val formattedStartDate = formatDateToMMDD(startDate) - val formattedEndDate = formatDateToMMDD(endDate) - - OutlinedCard( - colors = CardDefaults.cardColors( - containerColor = MaterialTheme.colorScheme.surface, - ), - border = BorderStroke(1.dp, md_theme_light_onSurfaceVariant), - modifier = Modifier - .fillMaxWidth() - .height(200.dp) - .padding(all = 16.dp) - .testTag("EventCard"), - ) { - Row( - modifier = Modifier.fillMaxSize(), - horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.CenterVertically, - ) { - Box( - modifier = Modifier - .fillMaxWidth() - .weight(2f) - ) { - Text( - text = organizer + "\n" + eventTitle, // 기관 명 + 행사 명 -> Text로 변경 - modifier = Modifier - .padding(16.dp) - .align(Alignment.CenterStart), - textAlign = TextAlign.Left, - fontSize = 16.sp, - fontFamily = poppins - ) - } - - Box( - modifier = Modifier - .fillMaxWidth() - .weight(1f) - ) { - - Column( - modifier = Modifier.fillMaxWidth(), - horizontalAlignment = Alignment.End - ) { - Text( - text = "$formattedStartDate - $formattedEndDate", - modifier = Modifier - .padding(16.dp) - .align(Alignment.End), - textAlign = TextAlign.Right, - fontFamily = poppins, - fontSize = 12.sp - ) - Text( - text = "♥ $likes", // 좋아요 수 -> Text로 변경 - modifier = Modifier - .padding(16.dp) - .align(Alignment.End), - textAlign = TextAlign.Right, - color = LikePink, - fontFamily = poppins - ) - } - } - } - } -} - 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 5ba6624..b0d0e00 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 @@ -1,407 +1,95 @@ package com.example.haengsha.ui.screens.home -import android.annotation.SuppressLint -import androidx.compose.foundation.Image -import androidx.compose.foundation.background -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column +import androidx.compose.animation.AnimatedContentTransitionScope +import androidx.compose.animation.core.tween import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size -import androidx.compose.foundation.layout.wrapContentHeight -import androidx.compose.material3.Button -import androidx.compose.material3.DatePicker -import androidx.compose.material3.DatePickerDialog -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.Text -import androidx.compose.material3.rememberDatePickerState import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.getValue -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.res.painterResource -import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp -import androidx.lifecycle.viewmodel.compose.viewModel -import com.example.haengsha.R -import com.example.haengsha.model.network.dataModel.EventResponse +import androidx.navigation.NavHostController +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import androidx.navigation.compose.rememberNavController +import com.example.haengsha.model.route.HomeRoute import com.example.haengsha.model.uiState.UserUiState -import com.example.haengsha.model.uiState.home.HomeApiUiState +import com.example.haengsha.model.viewModel.NavigationViewModel +import com.example.haengsha.model.viewModel.board.BoardApiViewModel +import com.example.haengsha.model.viewModel.board.BoardViewModel import com.example.haengsha.model.viewModel.home.HomeApiViewModel import com.example.haengsha.model.viewModel.home.HomeViewModel -import com.example.haengsha.ui.theme.HaengshaBlue -import com.example.haengsha.ui.theme.poppins -import com.example.haengsha.ui.uiComponents.CustomCircularProgressIndicator -import com.kizitonwose.calendar.compose.WeekCalendar -import com.kizitonwose.calendar.compose.weekcalendar.rememberWeekCalendarState -import com.kizitonwose.calendar.core.atStartOfMonth -import com.kizitonwose.calendar.core.firstDayOfWeekFromLocale -import com.kizitonwose.calendar.core.yearMonth -import java.text.SimpleDateFormat -import java.time.DayOfWeek +import com.example.haengsha.ui.screens.board.BoardDetailScreen import java.time.LocalDate import java.time.format.DateTimeFormatter -import java.time.format.TextStyle -import java.util.Calendar -import java.util.Date -import java.util.Locale - -private val dateFormatter = DateTimeFormatter.ofPattern("dd") -private val monthFormatter = DateTimeFormatter.ofPattern("MMMM") @Composable fun Home( homeViewModel: HomeViewModel, homeApiViewModel: HomeApiViewModel, + boardApiViewModel: BoardApiViewModel, + boardViewModel: BoardViewModel, + navigationViewModel: NavigationViewModel, + homeNavController: NavHostController = rememberNavController(), innerPadding: PaddingValues, userUiState: UserUiState ) { - HomeScreen(homeApiViewModel, innerPadding, userUiState, homeViewModel) -} - -@SuppressLint("UnusedMaterialScaffoldPaddingParameter") -@Composable -fun HomeScreen( - homeApiViewModel: HomeApiViewModel, - innerPadding: PaddingValues, - userUiState: UserUiState, - homeViewModel: HomeViewModel -) { - val homeApiUiState = homeApiViewModel.homeApiUiState - var selection by remember { mutableStateOf(LocalDate.now()) } - val currentMonth = selection.yearMonth - val startDate = remember { currentMonth.minusMonths(100).atStartOfMonth() } // Adjust as needed - val endDate = remember { currentMonth.plusMonths(100).atEndOfMonth() } // Adjust as needed - val firstDayOfWeek = remember { firstDayOfWeekFromLocale() } // Available from the library - - LaunchedEffect(selection) { - homeApiViewModel.getEventByDate(selection) - } - - val state = rememberWeekCalendarState( - startDate = startDate, - endDate = endDate, - firstVisibleWeekDate = selection, - firstDayOfWeek = firstDayOfWeek, - ) - - var showDatePicker by remember { - mutableStateOf(false) - } - - if (showDatePicker) { - MyDatePickerDialog( - onDateSelected = { selectedDate -> - selection = parseStringToDate(selectedDate) - showDatePicker = false // Close the date picker dialog - }, - onDismiss = { showDatePicker = false } - ) - } - - Column( - modifier = Modifier - .fillMaxSize() - .padding(innerPadding) + NavHost( + navController = homeNavController, + startDestination = HomeRoute.Home.route ) { - Box( - modifier = Modifier - .fillMaxWidth() - .height(50.dp) - ) { - // Center-aligned Text - Box( - modifier = Modifier - .padding(start = 16.dp) // Add padding to the left of the Text - .align(Alignment.Center) // Align the Text to the center-left - ) { - Text( - text = monthFormatter.format(selection.month), - fontFamily = poppins, - fontSize = 18.sp, - fontWeight = FontWeight.Medium - ) - } - - // Right-aligned Image - Box( - modifier = Modifier - .padding(end = 16.dp) // Add padding to the right of the Image - .align(Alignment.CenterEnd) // Align the Image to the center-right - .clickable { - showDatePicker = true - } - ) { - Image( - painter = painterResource(id = R.drawable.calendar_icon), - contentDescription = "calendar icon", - modifier = Modifier.size(24.dp) - - ) - } - } - - LaunchedEffect(selection) { - state.animateScrollToWeek(selection) + composable(HomeRoute.Home.route) { + navigationViewModel.updateRouteUiState("Home", HomeRoute.Home.route) + HomeScreen( + homeApiViewModel = homeApiViewModel, + innerPadding = innerPadding, + userUiState = userUiState, + homeViewModel = homeViewModel, + boardViewModel = boardViewModel, + homeNavController = homeNavController, + ) } - - WeekCalendar( - state = state, - userScrollEnabled = true, - calendarScrollPaged = true, - dayContent = { day -> - Day(day.date, isSelected = selection == day.date) { clicked -> - if (selection != clicked) { - selection = clicked + composable( + HomeRoute.HomeDetail.route, + enterTransition = { + when (initialState.destination.route) { + "Home" -> { + slideIntoContainer( + AnimatedContentTransitionScope.SlideDirection.Left, + animationSpec = tween(700) + ) } - } - }, - ) - - 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) - } - - is HomeApiUiState.Loading -> { - Column( - modifier = Modifier.fillMaxSize(), - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.Center, - ) { - CustomCircularProgressIndicator() - Spacer(modifier = Modifier.height(20.dp)) - Text( - text = "행사 불러오는 중...", - fontFamily = poppins, - fontSize = 20.sp, - fontWeight = FontWeight.SemiBold, - color = HaengshaBlue - ) - } - } - - is HomeApiUiState.HttpError -> { - Column( - modifier = Modifier.fillMaxSize(), - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.Center, - ) { - Text( - text = "이벤트를 불러오는 중 문제가 발생했어요.\n\n다시 시도해주세요.", - fontFamily = poppins, - fontSize = 18.sp, - fontWeight = FontWeight.SemiBold, - color = HaengshaBlue - ) - } - } - is HomeApiUiState.NetworkError -> { - Column( - modifier = Modifier.fillMaxSize(), - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.Center, - ) { - Text( - text = "인터넷 연결을 확인해주세요.", - fontFamily = poppins, - fontSize = 18.sp, - fontWeight = FontWeight.SemiBold, - color = HaengshaBlue - ) + else -> null } - } + }, + exitTransition = { + when (targetState.destination.route) { + "Home" -> { + slideOutOfContainer( + AnimatedContentTransitionScope.SlideDirection.Right, + animationSpec = tween(700) + ) + } - is HomeApiUiState.Error -> { - Column( - modifier = Modifier.fillMaxSize(), - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.Center, - ) { - Text( - text = "알 수 없는 문제가 발생했어요.\n\n메일로 문의해주세요.", - fontFamily = poppins, - fontSize = 18.sp, - fontWeight = FontWeight.SemiBold, - color = HaengshaBlue - ) + else -> null } } - } - - } -} - -@Composable -private fun Day(date: LocalDate, isSelected: Boolean, onClick: (LocalDate) -> Unit) { - Box( - modifier = Modifier - .fillMaxWidth() - .wrapContentHeight() - .clickable { onClick(date) }, - contentAlignment = Alignment.Center, - ) { - Column( - modifier = Modifier.padding(vertical = 10.dp), - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.spacedBy(6.dp), ) { - Text( - text = date.dayOfWeek.displayText(), - fontSize = 12.sp, - fontWeight = FontWeight.Light, - ) - Text( - text = dateFormatter.format(date), - fontSize = 14.sp, - fontWeight = FontWeight.Bold, - ) - } - if (isSelected) { - Box( - modifier = Modifier - .fillMaxWidth() - .height(5.dp) - .background(HaengshaBlue) - .align(Alignment.BottomCenter), + navigationViewModel.updateRouteUiState("Home", HomeRoute.HomeDetail.route) + BoardDetailScreen( + innerPadding = innerPadding, + boardApiViewModel = boardApiViewModel, + boardViewModel = boardViewModel, + userUiState = userUiState, + eventId = boardViewModel.eventId.value ) } } } -@OptIn(ExperimentalMaterial3Api::class) -@Composable -fun MyDatePickerDialog( - onDateSelected: (String) -> Unit, - onDismiss: () -> Unit -) { - val currentDate = LocalDate.now() - val initialDate = Calendar.getInstance() - initialDate.set(currentDate.year, currentDate.monthValue - 1, currentDate.dayOfMonth) - val datePickerState = rememberDatePickerState( - initialSelectedDateMillis = initialDate.timeInMillis, - yearRange = currentDate.year - 1..currentDate.year + 1 - ) - - val selectedDate = datePickerState.selectedDateMillis?.let { - convertMillisToDate(it) - } ?: "" - - DatePickerDialog( - onDismissRequest = { onDismiss() }, - confirmButton = { - Button(onClick = { - onDateSelected(selectedDate) - onDismiss() - } - - ) { - Text(text = "OK") - } - }, - dismissButton = { - Button(onClick = { - onDismiss() - }) { - Text(text = "Cancel") - } - } - ) { - DatePicker( - state = datePickerState, - showModeToggle = false - ) - } -} - -fun parseStringToDate(dateString: String): LocalDate? { - val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd") - return try { - LocalDate.parse(dateString, formatter) - } catch (e: Exception) { - null // Handle the case when the input string is not in the expected format - } -} - -fun DayOfWeek.displayText(uppercase: Boolean = false): String { - return getDisplayName(TextStyle.SHORT, Locale.ENGLISH).let { value -> - if (uppercase) value.uppercase(Locale.ENGLISH) else value - } -} - -private fun convertMillisToDate(millis: Long): String { - val formatter = SimpleDateFormat("yyyy-MM-dd", Locale.ROOT) - return formatter.format(Date(millis)) -} - -fun EventResponse.toEventCardData(): EventCardData { - val startDate = stringToDate(eventDurations[0].eventDay) - var endDate = startDate - if (eventDurations.size > 1) { - endDate = stringToDate(eventDurations[eventDurations.size - 1].eventDay) - } - - var eventType = "Festival" - if (!isFestival) { - eventType = "Academic" - } - return EventCardData( - organizer = author.nickname, - eventTitle = title, - startDate = startDate, - endDate = endDate, - likes = likeCount, - favorites = favoriteCount, - eventType = eventType, - place = place, - time = time ?: "wow" - ) -} - fun stringToDate(dateString: String): LocalDate { val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd") try { return LocalDate.parse(dateString, formatter) - //val format = SimpleDateFormat("yyyy-MM-dd HH:mm:ss") - //date = format.parse(dateString)!! } catch (e: Exception) { e.printStackTrace() } return LocalDate.now() } - -@Preview(showBackground = true) -@Composable -fun HomeScreenPreview() { - val homeViewModel = viewModel() - val homeApiViewModel: HomeApiViewModel = - viewModel(factory = HomeApiViewModel.Factory) - - Home( - homeViewModel = homeViewModel, - homeApiViewModel = homeApiViewModel, - innerPadding = PaddingValues(0.dp), - userUiState = UserUiState("foo", "bar") - ) -} \ No newline at end of file diff --git a/frontend/app/src/main/java/com/example/haengsha/ui/screens/home/HomeScreen.kt b/frontend/app/src/main/java/com/example/haengsha/ui/screens/home/HomeScreen.kt new file mode 100644 index 0000000..323dbee --- /dev/null +++ b/frontend/app/src/main/java/com/example/haengsha/ui/screens/home/HomeScreen.kt @@ -0,0 +1,314 @@ +package com.example.haengsha.ui.screens.home + +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +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.res.painterResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.navigation.NavController +import com.example.haengsha.R +import com.example.haengsha.model.dataSource.EventCardData +import com.example.haengsha.model.network.dataModel.EventResponse +import com.example.haengsha.model.uiState.UserUiState +import com.example.haengsha.model.uiState.home.HomeApiUiState +import com.example.haengsha.model.viewModel.board.BoardViewModel +import com.example.haengsha.model.viewModel.home.HomeApiViewModel +import com.example.haengsha.model.viewModel.home.HomeViewModel +import com.example.haengsha.ui.theme.HaengshaBlue +import com.example.haengsha.ui.theme.poppins +import com.example.haengsha.ui.uiComponents.CustomCircularProgressIndicator +import com.example.haengsha.ui.uiComponents.HomeDatePickerDialog +import com.kizitonwose.calendar.compose.WeekCalendar +import com.kizitonwose.calendar.compose.weekcalendar.rememberWeekCalendarState +import com.kizitonwose.calendar.core.atStartOfMonth +import com.kizitonwose.calendar.core.firstDayOfWeekFromLocale +import com.kizitonwose.calendar.core.yearMonth +import java.time.LocalDate +import java.time.format.DateTimeFormatter +import java.time.format.TextStyle +import java.util.Locale + +@Composable +fun HomeScreen( + homeApiViewModel: HomeApiViewModel, + innerPadding: PaddingValues, + userUiState: UserUiState, + homeViewModel: HomeViewModel, + boardViewModel: BoardViewModel, + homeNavController: NavController +) { + val dateFormatter = DateTimeFormatter.ofPattern("dd") + val monthFormatter = DateTimeFormatter.ofPattern("MM") + val fullFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd") + + val homeApiUiState = homeApiViewModel.homeApiUiState + val selection = homeViewModel.selectedDate.collectAsState().value + val currentMonth = selection.yearMonth + val startDate = remember { currentMonth.minusMonths(100).atStartOfMonth() } + val endDate = remember { currentMonth.plusMonths(100).atEndOfMonth() } + val firstDayOfWeek = remember { firstDayOfWeekFromLocale() } + + if (homeViewModel.initialEnter) { + LaunchedEffect(Unit) { homeApiViewModel.getEventByDate(selection) } + homeViewModel.initialEnter = false + } else { + if (homeViewModel.selectionChanged) { + LaunchedEffect(selection) { homeApiViewModel.getEventByDate(selection) } + } + } + + val state = rememberWeekCalendarState( + startDate = startDate, + endDate = endDate, + firstVisibleWeekDate = selection, + firstDayOfWeek = firstDayOfWeek, + ) + + var showDatePicker by remember { + mutableStateOf(false) + } + + if (showDatePicker) { + HomeDatePickerDialog( + onDateSelected = { selectedDate -> + homeViewModel.updateSelectedDate(LocalDate.parse(selectedDate, fullFormatter)) + showDatePicker = false + }, + onDismiss = { showDatePicker = false } + ) + } + + Column( + modifier = Modifier + .fillMaxSize() + .padding(innerPadding) + ) { + Box( + modifier = Modifier + .fillMaxWidth() + .height(50.dp) + ) { + Box( + modifier = Modifier + .padding(start = 16.dp) + .align(Alignment.Center) + ) { + Text( + modifier = Modifier.padding(top = 2.dp), + text = monthFormatter.format(selection) + "월" + " " + + dateFormatter.format(selection) + "일", + fontFamily = poppins, + fontSize = 18.sp, + fontWeight = FontWeight.Medium + ) + } + + Box( + modifier = Modifier + .padding(end = 16.dp) + .align(Alignment.CenterEnd) + .clickable { + showDatePicker = true + } + ) { + Image( + painter = painterResource(id = R.drawable.calendar_icon), + contentDescription = "calendar icon", + modifier = Modifier.size(24.dp) + + ) + } + } + + LaunchedEffect(selection) { + state.animateScrollToWeek(selection) + } + + WeekCalendar( + state = state, + userScrollEnabled = true, + calendarScrollPaged = true, + dayContent = { day -> + Day(day.date, isSelected = selection == day.date) { clicked -> + homeViewModel.updateSelectedDate(clicked) + } + }, + ) + + 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.selectionChanged = false + HomeScreenList( + homeViewModel = homeViewModel, + homeApiViewModel = homeApiViewModel, + homeNavController = homeNavController, + boardViewModel = boardViewModel, + userUiState = userUiState, + ) + } + + is HomeApiUiState.Loading -> { + Column( + modifier = Modifier.fillMaxSize(), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center, + ) { + CustomCircularProgressIndicator() + Spacer(modifier = Modifier.height(20.dp)) + Text( + text = "행사 불러오는 중...", + fontFamily = poppins, + fontSize = 20.sp, + fontWeight = FontWeight.SemiBold, + color = HaengshaBlue + ) + } + } + + is HomeApiUiState.HttpError -> { + Column( + modifier = Modifier.fillMaxSize(), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center, + ) { + Text( + text = "이벤트를 불러오는 중 문제가 발생했어요.\n\n다시 시도해주세요.", + fontFamily = poppins, + fontSize = 18.sp, + fontWeight = FontWeight.SemiBold, + color = HaengshaBlue + ) + } + } + + is HomeApiUiState.NetworkError -> { + Column( + modifier = Modifier.fillMaxSize(), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center, + ) { + Text( + text = "인터넷 연결을 확인해주세요.", + fontFamily = poppins, + fontSize = 18.sp, + fontWeight = FontWeight.SemiBold, + color = HaengshaBlue + ) + } + } + + is HomeApiUiState.Error -> { + Column( + modifier = Modifier.fillMaxSize(), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center, + ) { + Text( + text = "알 수 없는 문제가 발생했어요.\n\n메일로 문의해주세요.", + fontFamily = poppins, + fontSize = 18.sp, + fontWeight = FontWeight.SemiBold, + color = HaengshaBlue + ) + } + } + } + + } +} + + +@Composable +private fun Day(date: LocalDate, isSelected: Boolean, onClick: (LocalDate) -> Unit) { + val dateFormatter = DateTimeFormatter.ofPattern("dd") + + Box( + modifier = Modifier + .fillMaxWidth() + .wrapContentHeight() + .clickable { onClick(date) }, + contentAlignment = Alignment.Center, + ) { + Column( + modifier = Modifier.padding(vertical = 10.dp), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy(6.dp), + ) { + Text( + text = date.dayOfWeek.getDisplayName(TextStyle.SHORT, Locale.KOREAN), + fontSize = 12.sp, + fontWeight = FontWeight.Light, + ) + Text( + text = dateFormatter.format(date), + fontSize = 14.sp, + fontWeight = FontWeight.Bold, + ) + } + if (isSelected) { + Box( + modifier = Modifier + .fillMaxWidth() + .height(5.dp) + .background(HaengshaBlue) + .align(Alignment.BottomCenter), + ) + } + } +} + +private fun EventResponse.toEventCardData(): EventCardData { + val startDate = stringToDate(eventDurations[0].eventDay) + var endDate = startDate + if (eventDurations.size > 1) { + endDate = stringToDate(eventDurations[eventDurations.size - 1].eventDay) + } + + var eventType = "Festival" + if (!isFestival) { + eventType = "Academic" + } + return EventCardData( + id = id, + organizer = author.nickname, + eventTitle = title, + startDate = startDate, + endDate = endDate, + likes = likeCount, + favorites = favoriteCount, + eventType = eventType, + place = place, + time = time ?: "wow", + image = image ?: "image.jpg", + ) +} \ No newline at end of file diff --git a/frontend/app/src/main/java/com/example/haengsha/ui/screens/home/TabView.kt b/frontend/app/src/main/java/com/example/haengsha/ui/screens/home/HomeScreenList.kt similarity index 54% rename from frontend/app/src/main/java/com/example/haengsha/ui/screens/home/TabView.kt rename to frontend/app/src/main/java/com/example/haengsha/ui/screens/home/HomeScreenList.kt index b773988..5d5651f 100644 --- a/frontend/app/src/main/java/com/example/haengsha/ui/screens/home/TabView.kt +++ b/frontend/app/src/main/java/com/example/haengsha/ui/screens/home/HomeScreenList.kt @@ -1,7 +1,6 @@ package com.example.haengsha.ui.screens.home import androidx.compose.foundation.ExperimentalFoundationApi -import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement @@ -14,15 +13,12 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width -import androidx.compose.foundation.layout.wrapContentHeight -import androidx.compose.foundation.layout.wrapContentWidth import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.foundation.pager.HorizontalPager import androidx.compose.foundation.pager.rememberPagerState -import androidx.compose.material3.AlertDialog +import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Button import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -35,78 +31,60 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.drawBehind import androidx.compose.ui.draw.shadow import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.text.font.Font -import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import coil.compose.AsyncImage -import coil.request.ImageRequest -import com.example.haengsha.R +import androidx.compose.ui.window.Dialog +import androidx.navigation.NavController +import com.example.haengsha.model.dataSource.TabItem +import com.example.haengsha.model.route.HomeRoute import com.example.haengsha.model.uiState.UserUiState import com.example.haengsha.model.uiState.home.RecommendationApiUiState +import com.example.haengsha.model.viewModel.board.BoardViewModel import com.example.haengsha.model.viewModel.home.HomeApiViewModel import com.example.haengsha.model.viewModel.home.HomeViewModel import com.example.haengsha.ui.theme.HaengshaBlue -import com.example.haengsha.ui.theme.LikePink +import com.example.haengsha.ui.theme.md_theme_light_surface import com.example.haengsha.ui.theme.poppins import com.example.haengsha.ui.uiComponents.CustomCircularProgressIndicator +import com.example.haengsha.ui.uiComponents.CustomHorizontalDivider +import com.example.haengsha.ui.uiComponents.HomeListItem import kotlinx.coroutines.launch -import java.time.LocalDate - -data class TabItem( - val title: String, val eventCards: List -) - -data class EventCardData( - val organizer: String, - val eventTitle: String, - val startDate: LocalDate, - val endDate: LocalDate, - val likes: Int, - val favorites: Int, - val eventType: String, - val place: String = "", - val time: String = "", - val image: String = "" -) @OptIn(ExperimentalFoundationApi::class) @Composable -fun TabView( +fun HomeScreenList( homeViewModel: HomeViewModel, homeApiViewModel: HomeApiViewModel, + homeNavController: NavController, + boardViewModel: BoardViewModel, userUiState: UserUiState ) { + val homeContext = LocalContext.current + val configuration = LocalConfiguration.current + val deviceWidth = configuration.screenWidthDp.dp + val deviceHeight = configuration.screenHeightDp.dp + val academicItems by homeViewModel.academicItems.observeAsState() val festivalItems by homeViewModel.festivalItems.observeAsState() val recommendationApiUiState = homeApiViewModel.recommendationApiUiState - var showDialog by remember { mutableStateOf(false) } - var selectedEvent: EventCardData? by remember { mutableStateOf(null) } - var showEventCardPopup by remember { mutableStateOf(false) } - val tabItems = listOf(academicItems?.let { - TabItem( - title = "Academic", eventCards = it - ) - }, festivalItems?.let { - TabItem( - title = "Festival", eventCards = it - ) - }) - // Remember the selected tab + var showRecommendDialog by remember { mutableStateOf(false) } + val tabItems = listOf( + academicItems?.let { TabItem(title = "Academic", eventCards = it) }, + festivalItems?.let { TabItem(title = "Festival", eventCards = it) } + ) var selectedTabIndex by remember { mutableIntStateOf(0) } val coroutineScope = rememberCoroutineScope() - // Pager state val pagerState = rememberPagerState(pageCount = { tabItems.size }) - val eventContext = LocalContext.current Column(modifier = Modifier.fillMaxSize()) { Row( @@ -183,9 +161,10 @@ fun TabView( ) { Button( onClick = { - showDialog = true - if (userUiState.role != "Group") { - homeApiViewModel.getRecommendationList(token = userUiState.token) + showRecommendDialog = true + if (userUiState.role != "Group" && homeViewModel.initialRecommendationState) { + homeApiViewModel.getRecommendationList(userUiState.token) + homeViewModel.initialRecommendationState = false } }, colors = androidx.compose.material3.ButtonDefaults.buttonColors(HaengshaBlue), @@ -206,6 +185,7 @@ fun TabView( ) { Text( + modifier = Modifier.padding(top = 2.dp), text = "행사 추천 받기", fontSize = 18.sp, fontFamily = poppins, @@ -214,7 +194,6 @@ fun TabView( ) } } - // Pager HorizontalPager( state = pagerState, modifier = Modifier.fillMaxWidth(), @@ -222,7 +201,6 @@ fun TabView( ) { index -> selectedTabIndex = if (index == 1) 1 else 0 val itemsToDisplay = if (index == 0) festivalItems else academicItems - // App content if (itemsToDisplay.isNullOrEmpty()) { Box( @@ -247,15 +225,18 @@ fun TabView( ) { items(itemsToDisplay) { item -> Box(modifier = Modifier.clickable { - showEventCardPopup = true - selectedEvent = item + boardViewModel.updateEventId(item.id) + homeNavController.navigate(HomeRoute.HomeDetail.route) }) { - EventCard( + HomeListItem( organizer = item.organizer, eventTitle = item.eventTitle, + image = item.image, startDate = item.startDate, endDate = item.endDate, likes = item.likes, + eventType = item.eventType, + homeContext = homeContext ) } } @@ -264,43 +245,22 @@ fun TabView( } } - if (showDialog) { - var recommendationTitle by remember { mutableStateOf("") } + if (showRecommendDialog) { + var recommendationTitle by remember { mutableStateOf("\n") } - // Display the AlertDialog with "Here is popup" - AlertDialog( - onDismissRequest = { - // Close the dialog when clicked outside - showDialog = false - }, - modifier = Modifier - .shadow( - elevation = 10.dp, - spotColor = Color(0x40000000), - ambientColor = Color(0x40000000) - ) - .width(if (userUiState.role == "Group") 300.dp else 500.dp) - .height(if (userUiState.role == "Group") 300.dp else 500.dp) - .background(color = Color.White), - containerColor = Color.White, - title = { - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.Center - ) { - Text( - text = recommendationTitle, - fontSize = 16.sp, - fontFamily = poppins, - fontWeight = FontWeight(500), - color = Color(0xFF000000), - textAlign = TextAlign.Center, - ) - } - }, text = { + Dialog(onDismissRequest = { showRecommendDialog = false }) { + Column( + modifier = Modifier + .width(if (userUiState.role == "Group") 300.dp else deviceWidth) + .height(if (userUiState.role == "Group") 300.dp else deviceHeight - 130.dp) + .clip(RoundedCornerShape(10.dp)) + .background(md_theme_light_surface) + ) { if (userUiState.role == "Group") { Box( - modifier = Modifier.fillMaxSize(), + modifier = Modifier + .fillMaxWidth() + .height(250.dp), contentAlignment = Alignment.Center ) { Text( @@ -312,8 +272,24 @@ fun TabView( ) } } else { + Text( + text = recommendationTitle, + modifier = Modifier + .fillMaxWidth() + .padding(top = 10.dp), + fontSize = 16.sp, + fontFamily = poppins, + fontWeight = FontWeight(500), + color = Color(0xFF000000), + textAlign = TextAlign.Center + ) + Spacer(modifier = Modifier.height(10.dp)) + CustomHorizontalDivider(color = Color.Black.copy(0.3f)) LazyColumn( - modifier = Modifier.fillMaxSize(), + modifier = Modifier + .fillMaxWidth() + .height(deviceHeight - 250.dp) + .background(Color.White), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center ) { @@ -343,13 +319,23 @@ fun TabView( stringToDate(event.eventDurations[event.eventDurations.size - 1].eventDay) } - EventCard( - organizer = event.author.nickname, - eventTitle = event.title, - startDate = startDate, - endDate = endDate, - likes = event.likeCount, - ) + Box(modifier = Modifier.clickable { + boardViewModel.updateEventId(event.id) + showRecommendDialog = false + homeNavController.navigate(HomeRoute.HomeDetail.route) + }) { + HomeListItem( + organizer = event.author.nickname, + eventTitle = event.title, + image = event.image, + startDate = startDate, + endDate = endDate, + likes = event.likeCount, + eventType = if (event.isFestival) "Festival" else "Academic", + homeContext = homeContext + ) + } + } } } @@ -371,11 +357,13 @@ fun TabView( is RecommendationApiUiState.HttpError -> { items(1) { Text( - text = "추천 행사를 불러오는 중 문제가 발생했어요!\n\n다시 시도해주세요.", + text = "추천 행사를 불러오는 중\n문제가 발생했어요!\n\n다시 시도해주세요.", fontFamily = poppins, - fontSize = 16.sp, + fontSize = 20.sp, fontWeight = FontWeight.SemiBold, - color = HaengshaBlue + color = Color.Black, + lineHeight = 25.sp, + textAlign = TextAlign.Center ) } } @@ -406,231 +394,25 @@ fun TabView( } } } - }, - confirmButton = { - Box( - contentAlignment = Alignment.Center, + CustomHorizontalDivider(color = Color.Black.copy(0.3f)) + Row( modifier = Modifier - .fillMaxWidth() - .padding(0.dp) - ) { - Button( - onClick = { - showDialog = false - }, - modifier = Modifier - .wrapContentWidth() - .wrapContentHeight() - .padding(0.dp), // 패딩 제거 - - colors = androidx.compose.material3.ButtonDefaults.buttonColors(Color.White), - - ) { - Text( - text = "닫기", - fontSize = 16.sp, - fontFamily = poppins, - fontWeight = FontWeight(500), - color = Color(0xFF000000), - textAlign = TextAlign.Center, - textDecoration = TextDecoration.Underline, - modifier = Modifier.padding(0.dp) // 텍스트 주위의 패딩 제거 - ) - } - } - } - ) - } - - if (showEventCardPopup) { - AlertDialog( - onDismissRequest = { - // Close the popup when clicked outside - showEventCardPopup = false - }, - title = { - Column( - verticalArrangement = Arrangement.spacedBy( - 8.dp, Alignment.CenterVertically - ), - horizontalAlignment = Alignment.Start, + .fillMaxSize() + .clickable { showRecommendDialog = false }, + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.Center ) { - Text( - text = selectedEvent?.eventTitle ?: "N/A", - fontSize = 18.sp, - lineHeight = 20.sp, - fontFamily = FontFamily(Font(R.font.poppins_bold)), - fontWeight = FontWeight(400), - color = Color(0xFF343A40), + text = "닫기", + fontSize = 16.sp, + fontFamily = poppins, + fontWeight = FontWeight.Medium, + textAlign = TextAlign.Center, + textDecoration = TextDecoration.Underline, ) - - Row { - - Text( - text = selectedEvent?.eventType ?: "N/A", - fontSize = 11.sp, - lineHeight = 17.sp, - fontFamily = poppins, - fontWeight = FontWeight(400), - color = Color(0xFF868E96), - ) - Text( - text = " | ", - fontSize = 11.sp, - lineHeight = 17.sp, - fontFamily = poppins, - fontWeight = FontWeight(400), - color = Color(0xFF868E96), - ) - - Text( - text = selectedEvent?.organizer ?: "N/A", - fontSize = 11.sp, - lineHeight = 17.sp, - fontFamily = poppins, - fontWeight = FontWeight(400), - color = Color(0xFF868E96), - ) - } - - } - }, - text = { - // Use a Column to ensure proper spacing of text - Column { - Box( - modifier = Modifier - .fillMaxWidth() - .padding(8.dp), // Adjust the padding as needed - contentAlignment = Alignment.Center - - ) { - /*Image( - painter = painterResource(id = R.drawable.nudge_image), - contentDescription = "image description", - contentScale = ContentScale.Crop, // Maintain aspect ratio - modifier = Modifier.fillMaxWidth() - )*/ - if (selectedEvent?.image?.isNotEmpty() == true) { - AsyncImage( - model = ImageRequest.Builder(context = eventContext) - .data(selectedEvent?.image) - .crossfade(true) - .build(), - contentDescription = "poster", - modifier = Modifier.size(360.dp) - ) - } - } - - Column { - - val startDateText = selectedEvent?.startDate?.let { formatDateToMMDD(it) } - val endDateText = selectedEvent?.endDate?.let { formatDateToMMDD(it) } - - - Text( - text = "주최 | " + selectedEvent?.organizer, - fontSize = 12.sp, - lineHeight = 19.56.sp, - fontFamily = poppins, - fontWeight = FontWeight(500), - color = Color(0xFF000000), - textAlign = TextAlign.Center, - ) - - Text( - text = "일자 | $startDateText - $endDateText", - fontSize = 12.sp, - lineHeight = 19.56.sp, - fontFamily = poppins, - fontWeight = FontWeight(500), - color = Color(0xFF000000), - textAlign = TextAlign.Center, - ) - - Text( - text = "장소 | " + selectedEvent?.place, - fontSize = 12.sp, - lineHeight = 19.56.sp, - fontFamily = poppins, - fontWeight = FontWeight(500), - color = Color(0xFF000000), - textAlign = TextAlign.Center, - ) - - Text( - text = "시간 | " + selectedEvent?.time, - fontSize = 12.sp, - lineHeight = 19.56.sp, - fontFamily = poppins, - fontWeight = FontWeight(500), - color = Color(0xFF000000), - textAlign = TextAlign.Center, - ) - - Row(modifier = Modifier.padding(top = 10.dp)) { - Image( - painter = painterResource(id = R.drawable.like_fill_icon), - contentDescription = "image description", - ) - - Text( - text = selectedEvent?.likes.toString(), - fontSize = 10.sp, - fontFamily = poppins, - fontWeight = FontWeight(500), - color = LikePink, - textAlign = TextAlign.Center, - ) - } - } - } - }, - confirmButton = { - Box( - contentAlignment = Alignment.Center, - modifier = Modifier - .fillMaxWidth() - .padding(0.dp) - ) { - Button( - onClick = { - showEventCardPopup = false - }, - modifier = Modifier - .wrapContentWidth() - .wrapContentHeight() - .padding(0.dp), // 패딩 제거 - - colors = androidx.compose.material3.ButtonDefaults.buttonColors(Color.White), - - ) { - Text( - text = "닫기", - fontSize = 13.sp, - fontFamily = poppins, - fontWeight = FontWeight(500), - color = Color(0xFF000000), - textAlign = TextAlign.Center, - textDecoration = TextDecoration.Underline, - modifier = Modifier.padding(0.dp) // 텍스트 주위의 패딩 제거 - ) - } } - }, - modifier = Modifier - .shadow( - elevation = 10.dp, - spotColor = Color(0x40000000), - ambientColor = Color(0x40000000) - ) - .width(300.dp) - .height(550.dp) - .background(color = Color(0xFFFFFFFF)), - containerColor = Color(0xFFFFFFFF) - ) + } + } } } 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 f1ac218..4b6627c 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 @@ -49,6 +49,7 @@ import com.example.haengsha.model.uiState.board.BoardUiState import com.example.haengsha.model.viewModel.board.BoardViewModel import com.example.haengsha.ui.theme.BackgroundGrey import com.example.haengsha.ui.theme.ButtonBlue +import com.example.haengsha.ui.theme.FieldStrokeRed import com.example.haengsha.ui.theme.HaengshaBlue import com.example.haengsha.ui.theme.HaengshaGrey import com.example.haengsha.ui.theme.md_theme_light_onPrimary @@ -189,14 +190,33 @@ fun FilterDialog( .shadow(elevation = 5.dp, shape = RoundedCornerShape(15.dp)) .background(color = md_theme_light_onPrimary), ) { - Spacer(modifier = Modifier.height(20.dp)) - Text( + Spacer(modifier = Modifier.height(25.dp)) + Row( modifier = Modifier.padding(horizontal = 15.dp), - text = "필터 설정", - fontFamily = poppins, - fontSize = 20.sp, - fontWeight = FontWeight.SemiBold - ) + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = "필터 설정", + fontFamily = poppins, + fontSize = 20.sp, + fontWeight = FontWeight.SemiBold + ) + Spacer(modifier = Modifier.weight(1f)) + Box( + modifier = Modifier + .border(1.dp, FieldStrokeRed.copy(0.7f), RoundedCornerShape(6.dp)) + .clickable { boardViewModel.resetFilter() } + .padding(start = 5.dp, end = 5.dp, top = 2.dp) + ) { + Text( + text = "필터 초기화", + fontFamily = poppins, + fontSize = 12.sp, + fontWeight = FontWeight.Medium, + color = FieldStrokeRed.copy(0.7f) + ) + } + } Spacer(modifier = Modifier.height(20.dp)) CustomHorizontalDivider(color = HaengshaGrey) Spacer(modifier = Modifier.height(20.dp)) @@ -392,7 +412,10 @@ fun FilterDialog( verticalAlignment = Alignment.CenterVertically ) { ModalCancelButton( - onClick = onDismissRequest + onClick = { + onDismissRequest() + boardViewModel.cancelFilter() + } ) Spacer(modifier = Modifier.weight(1f)) ModalConfirmButton( @@ -401,7 +424,6 @@ fun FilterDialog( if (boardUiState.keyword.isEmpty()) { Toasty.warning(context, "검색 후 필터를 적용해주세요", Toast.LENGTH_SHORT, true) .show() - boardViewModel.resetFilterInitialState() } else if (!boardViewModel.isSearched.value) { Toasty.warning( context, @@ -420,7 +442,7 @@ fun FilterDialog( boardUiState.endDate ) ) - boardViewModel.updateFilterInitialState() + boardViewModel.savePreviousFilter() } onDismissRequest() } @@ -434,7 +456,7 @@ fun FilterDialog( @OptIn(ExperimentalMaterial3Api::class) @Composable -fun CustomDatePickerDialog( +fun BoardDatePickerDialog( onDismissRequest: () -> Unit, boardViewModel: BoardViewModel, type: String, @@ -511,6 +533,39 @@ fun CustomDatePickerDialog( } } -//@Preview(showBackground = true) -//@Composable -//fun MessageDialogPreview() {} \ No newline at end of file +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun HomeDatePickerDialog( + onDateSelected: (String) -> Unit, + onDismiss: () -> Unit +) { + val currentDate = LocalDate.now() + val initialDate = Calendar.getInstance() + initialDate.set(currentDate.year, currentDate.monthValue - 1, currentDate.dayOfMonth) + val datePickerState = rememberDatePickerState( + initialSelectedDateMillis = initialDate.timeInMillis, + yearRange = currentDate.year - 1..currentDate.year + 1 + ) + val formatter = SimpleDateFormat("yyyy-MM-dd", Locale.ROOT) + val selectedDate = datePickerState.selectedDateMillis?.let { + formatter.format(Date(it)) + } ?: "" + + DatePickerDialog( + onDismissRequest = { onDismiss() }, + confirmButton = { + Button(onClick = { + onDateSelected(selectedDate) + onDismiss() + }) { Text(text = "확인") } + }, + dismissButton = { + Button(onClick = { onDismiss() }) { Text(text = "취소") } + } + ) { + DatePicker( + state = datePickerState, + showModeToggle = false + ) + } +} \ No newline at end of file diff --git a/frontend/app/src/main/java/com/example/haengsha/ui/uiComponents/ListItem.kt b/frontend/app/src/main/java/com/example/haengsha/ui/uiComponents/ListItem.kt index 4bf57f7..d60147e 100644 --- a/frontend/app/src/main/java/com/example/haengsha/ui/uiComponents/ListItem.kt +++ b/frontend/app/src/main/java/com/example/haengsha/ui/uiComponents/ListItem.kt @@ -1,11 +1,15 @@ package com.example.haengsha.ui.uiComponents +import android.content.Context import androidx.compose.foundation.Image import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding @@ -13,29 +17,48 @@ import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.widthIn import androidx.compose.foundation.layout.wrapContentWidth +import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Icon import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalConfiguration +import androidx.compose.ui.platform.testTag +import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.vectorResource import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import androidx.compose.ui.zIndex +import coil.compose.AsyncImage +import coil.compose.AsyncImagePainter +import coil.compose.rememberAsyncImagePainter +import coil.request.ImageRequest +import coil.size.Size import com.example.haengsha.R +import com.example.haengsha.model.dataSource.SampleImage import com.example.haengsha.model.network.dataModel.BoardListResponse import com.example.haengsha.ui.theme.HaengshaBlue import com.example.haengsha.ui.theme.HaengshaGrey import com.example.haengsha.ui.theme.LikePink import com.example.haengsha.ui.theme.PlaceholderGrey +import com.example.haengsha.ui.theme.md_theme_light_surface import com.example.haengsha.ui.theme.poppins +import java.time.LocalDate +import java.time.format.DateTimeFormatter @Composable -fun listItem( +fun boardListItem( isFavorite: Boolean, event: BoardListResponse ): Int { @@ -153,7 +176,179 @@ fun listItem( } @Composable -fun CommentList( +fun HomeListItem( + organizer: String, + eventTitle: String, + image: String?, + startDate: LocalDate, + endDate: LocalDate, + likes: Int, + eventType: String, + homeContext: Context +) { + val configuration = LocalConfiguration.current + val deviceWidth = configuration.screenWidthDp.dp + val deviceHeight = configuration.screenHeightDp.dp + + val formatter = DateTimeFormatter.ofPattern("MM-dd") + val eventDuration = startDate.format(formatter) + " ~ " + endDate.format(formatter) + + val randomFestivalId by rememberSaveable { mutableIntStateOf((0..9).random()) } + val randomAcademicId by rememberSaveable { mutableIntStateOf((10..19).random()) } + + Row( + modifier = Modifier + .fillMaxWidth() + .height(deviceHeight / 5) + .padding(horizontal = 10.dp, vertical = 5.dp) + .testTag("EventCard"), + verticalAlignment = Alignment.CenterVertically + ) { + Box( + modifier = Modifier + .size(deviceHeight / 6) + .border(1.dp, Color.Black, RoundedCornerShape(10.dp)), + contentAlignment = Alignment.Center + ) { + if ((image?.isNotEmpty() == true && image != "image.jpg")) { + val imageModel = ImageRequest.Builder(context = homeContext) + .data(image) + .size(Size.ORIGINAL) + .build() + val painter = rememberAsyncImagePainter(model = imageModel) + if (painter.state is AsyncImagePainter.State.Error) { + Image( + painter = painterResource(SampleImage.ImageAcademicDefault.id), + contentDescription = "sample image", + modifier = Modifier + .fillMaxSize() + .clip(RoundedCornerShape(10.dp)), + alignment = Alignment.Center, + contentScale = ContentScale.Crop + ) + } else { + AsyncImage( + model = imageModel, + contentDescription = "festival poster", + modifier = Modifier + .fillMaxSize() + .clip(RoundedCornerShape(10.dp)), + alignment = Alignment.Center, + contentScale = ContentScale.Crop + ) + } + } else { + val imageId = if (eventType == "Festival") { + SampleImage.entries[randomFestivalId].id + } else { + SampleImage.entries[randomAcademicId].id + } + Image( + painter = painterResource(imageId), + contentDescription = "sample image", + modifier = Modifier + .fillMaxSize() + .clip(RoundedCornerShape(10.dp)), + alignment = Alignment.Center, + contentScale = ContentScale.Crop + ) + } + } + Box( + modifier = Modifier + .fillMaxWidth() + .height(deviceHeight / 7) + ) { + Box( + modifier = Modifier + .height(deviceHeight / 7) + .width(1.dp) + .zIndex(1f), + contentAlignment = Alignment.Center + ) { + Box( + modifier = Modifier + .width(1.dp) + .height(deviceHeight / 7 - 2.dp) + .background(md_theme_light_surface) + .zIndex(1f) + ) + } + Column( + modifier = Modifier + .fillMaxSize() + .border( + 1.dp, Color.Black, + RoundedCornerShape(topEnd = 10.dp, bottomEnd = 10.dp) + ), + verticalArrangement = Arrangement.SpaceBetween + ) { + Text( + text = eventDuration, + modifier = Modifier + .fillMaxWidth() + .padding(top = 5.dp, end = 10.dp), + fontFamily = poppins, + fontSize = 10.sp, + fontWeight = FontWeight.Normal, + color = Color.Black, + textAlign = TextAlign.End + ) + Column(modifier = Modifier.padding(start = 8.dp)) { + Text( + text = organizer, + modifier = Modifier.widthIn(max = deviceWidth / 2f), + fontFamily = poppins, + fontSize = 17.sp, + fontWeight = FontWeight.SemiBold, + color = Color.Black, + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + Spacer(modifier = Modifier.height(2.dp)) + Text( + text = eventTitle, + modifier = Modifier.widthIn(max = deviceWidth / 1.8f), + fontFamily = poppins, + fontSize = 15.sp, + fontWeight = FontWeight.Normal, + color = Color.Black, + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + } + Row( + modifier = Modifier + .fillMaxWidth() + .padding(bottom = 3.dp, end = 10.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.End + ) { + Icon( + modifier = Modifier + .size(12.dp) + .padding(top = 1.dp), + imageVector = ImageVector.vectorResource(id = R.drawable.like_fill_icon), + contentDescription = "like icon", + tint = LikePink + ) + Spacer(modifier = Modifier.width(5.dp)) + Text( + text = likes.toString(), + modifier = Modifier.padding(top = 2.dp), + fontFamily = poppins, + fontSize = 12.sp, + fontWeight = FontWeight.Normal, + color = LikePink + ) + } + } + } + } +} + +@Composable +fun CommentListItem( userNickName: String, commentDate: String, commentContent: String diff --git a/frontend/app/src/main/res/drawable-nodpi/a_aiseminar.jpg b/frontend/app/src/main/res/drawable-nodpi/a_aiseminar.jpg new file mode 100644 index 0000000..41bfc39 Binary files /dev/null and b/frontend/app/src/main/res/drawable-nodpi/a_aiseminar.jpg differ diff --git a/frontend/app/src/main/res/drawable-nodpi/a_artspace.png b/frontend/app/src/main/res/drawable-nodpi/a_artspace.png new file mode 100644 index 0000000..882bf4b Binary files /dev/null and b/frontend/app/src/main/res/drawable-nodpi/a_artspace.png differ diff --git a/frontend/app/src/main/res/drawable-nodpi/a_bookconcert.jpg b/frontend/app/src/main/res/drawable-nodpi/a_bookconcert.jpg new file mode 100644 index 0000000..0fbe817 Binary files /dev/null and b/frontend/app/src/main/res/drawable-nodpi/a_bookconcert.jpg differ diff --git a/frontend/app/src/main/res/drawable-nodpi/a_law.jpg b/frontend/app/src/main/res/drawable-nodpi/a_law.jpg new file mode 100644 index 0000000..eb9c886 Binary files /dev/null and b/frontend/app/src/main/res/drawable-nodpi/a_law.jpg differ diff --git a/frontend/app/src/main/res/drawable-nodpi/a_math.jpg b/frontend/app/src/main/res/drawable-nodpi/a_math.jpg new file mode 100644 index 0000000..49d0dc7 Binary files /dev/null and b/frontend/app/src/main/res/drawable-nodpi/a_math.jpg differ diff --git a/frontend/app/src/main/res/drawable-nodpi/a_music.png b/frontend/app/src/main/res/drawable-nodpi/a_music.png new file mode 100644 index 0000000..6956cd7 Binary files /dev/null and b/frontend/app/src/main/res/drawable-nodpi/a_music.png differ diff --git a/frontend/app/src/main/res/drawable-nodpi/a_network.jpg b/frontend/app/src/main/res/drawable-nodpi/a_network.jpg new file mode 100644 index 0000000..2769243 Binary files /dev/null and b/frontend/app/src/main/res/drawable-nodpi/a_network.jpg differ diff --git a/frontend/app/src/main/res/drawable-nodpi/a_piano.jpg b/frontend/app/src/main/res/drawable-nodpi/a_piano.jpg new file mode 100644 index 0000000..0a77988 Binary files /dev/null and b/frontend/app/src/main/res/drawable-nodpi/a_piano.jpg differ diff --git a/frontend/app/src/main/res/drawable-nodpi/a_snu_enterance.jpg b/frontend/app/src/main/res/drawable-nodpi/a_snu_enterance.jpg new file mode 100644 index 0000000..80512a7 Binary files /dev/null and b/frontend/app/src/main/res/drawable-nodpi/a_snu_enterance.jpg differ diff --git a/frontend/app/src/main/res/drawable-nodpi/a_social.png b/frontend/app/src/main/res/drawable-nodpi/a_social.png new file mode 100644 index 0000000..19d0596 Binary files /dev/null and b/frontend/app/src/main/res/drawable-nodpi/a_social.png differ diff --git a/frontend/app/src/main/res/drawable-nodpi/a_writing.jpg b/frontend/app/src/main/res/drawable-nodpi/a_writing.jpg new file mode 100644 index 0000000..de0ae38 Binary files /dev/null and b/frontend/app/src/main/res/drawable-nodpi/a_writing.jpg differ diff --git a/frontend/app/src/main/res/drawable-nodpi/f_alchole.jpg b/frontend/app/src/main/res/drawable-nodpi/f_alchole.jpg new file mode 100644 index 0000000..7a4dd3b Binary files /dev/null and b/frontend/app/src/main/res/drawable-nodpi/f_alchole.jpg differ diff --git a/frontend/app/src/main/res/drawable-nodpi/f_animu.jpg b/frontend/app/src/main/res/drawable-nodpi/f_animu.jpg new file mode 100644 index 0000000..b1229c2 Binary files /dev/null and b/frontend/app/src/main/res/drawable-nodpi/f_animu.jpg differ diff --git a/frontend/app/src/main/res/drawable-nodpi/f_cinema.jpg b/frontend/app/src/main/res/drawable-nodpi/f_cinema.jpg new file mode 100644 index 0000000..eacc183 Binary files /dev/null and b/frontend/app/src/main/res/drawable-nodpi/f_cinema.jpg differ diff --git a/frontend/app/src/main/res/drawable-nodpi/f_cushion.jpg b/frontend/app/src/main/res/drawable-nodpi/f_cushion.jpg new file mode 100644 index 0000000..c50580d Binary files /dev/null and b/frontend/app/src/main/res/drawable-nodpi/f_cushion.jpg differ diff --git a/frontend/app/src/main/res/drawable-nodpi/f_dongsojae.jpg b/frontend/app/src/main/res/drawable-nodpi/f_dongsojae.jpg new file mode 100644 index 0000000..c9088c5 Binary files /dev/null and b/frontend/app/src/main/res/drawable-nodpi/f_dongsojae.jpg differ diff --git a/frontend/app/src/main/res/drawable-nodpi/f_goahead.jpg b/frontend/app/src/main/res/drawable-nodpi/f_goahead.jpg new file mode 100644 index 0000000..27d538e Binary files /dev/null and b/frontend/app/src/main/res/drawable-nodpi/f_goahead.jpg differ diff --git a/frontend/app/src/main/res/drawable-nodpi/f_meeting.jpg b/frontend/app/src/main/res/drawable-nodpi/f_meeting.jpg new file mode 100644 index 0000000..d036bba Binary files /dev/null and b/frontend/app/src/main/res/drawable-nodpi/f_meeting.jpg differ diff --git a/frontend/app/src/main/res/drawable-nodpi/f_pub.jpg b/frontend/app/src/main/res/drawable-nodpi/f_pub.jpg new file mode 100644 index 0000000..82a6e9d Binary files /dev/null and b/frontend/app/src/main/res/drawable-nodpi/f_pub.jpg differ diff --git a/frontend/app/src/main/res/drawable-nodpi/f_recruite.jpg b/frontend/app/src/main/res/drawable-nodpi/f_recruite.jpg new file mode 100644 index 0000000..2e75638 Binary files /dev/null and b/frontend/app/src/main/res/drawable-nodpi/f_recruite.jpg differ diff --git a/frontend/app/src/main/res/drawable-nodpi/f_taco.jpg b/frontend/app/src/main/res/drawable-nodpi/f_taco.jpg new file mode 100644 index 0000000..7fe502a Binary files /dev/null and b/frontend/app/src/main/res/drawable-nodpi/f_taco.jpg differ diff --git a/frontend/app/src/test/java/com/example/haengsha/unitTest/board/BoardViewModelTest.kt b/frontend/app/src/test/java/com/example/haengsha/unitTest/board/BoardViewModelTest.kt index eeaaa6e..7ddde77 100644 --- a/frontend/app/src/test/java/com/example/haengsha/unitTest/board/BoardViewModelTest.kt +++ b/frontend/app/src/test/java/com/example/haengsha/unitTest/board/BoardViewModelTest.kt @@ -12,106 +12,130 @@ class BoardViewModelTest { private val viewModel = BoardViewModel() @Test - fun boardViewBoard_updateEventId_updateIsCorrect() { + fun boardViewModel_updateEventId_updateIsCorrect() { viewModel.updateEventId(1) assertEquals(viewModel.eventId.value, 1) } @Test - fun boardViewBoard_updateInput_updateIsCorrect() { + fun boardViewModel_updateInput_updateIsCorrect() { viewModel.updateInput("input") assertEquals(viewModel.input.value, "input") } @Test - fun boardViewBoard_setIsSearchedTrue_isSearchedIsTrue() { + fun boardViewModel_setIsSearchedTrue_isSearchedIsTrue() { viewModel.setIsSearchedTrue() assertTrue(viewModel.isSearched.value) } @Test - fun boardViewBoard_setIsSearchedFalse_isSearchedIsFalse() { + fun boardViewModel_setIsSearchedFalse_isSearchedIsFalse() { viewModel.setIsSearchedFalse() assertFalse(viewModel.isSearched.value) } @Test - fun boardViewBoard_isError_errorIsTrue() { + fun boardViewModel_isError_errorIsTrue() { viewModel.isError() assertTrue(viewModel.isError) } @Test - fun boardViewBoard_resetError_errorIsFalse() { + fun boardViewModel_resetError_errorIsFalse() { viewModel.isError() viewModel.resetError() assertFalse(viewModel.isError) } @Test - fun boardViewBoard_saveToken_saveIsCorrect() { + fun boardViewModel_saveToken_saveIsCorrect() { viewModel.saveToken("token") assertEquals(viewModel.boardUiState.value.token, "Token token") } @Test - fun boardViewBoard_updateKeyword_updateIsCorrect() { + fun boardViewModel_updateKeyword_updateIsCorrect() { viewModel.updateKeyword("keyword") assertEquals(viewModel.boardUiState.value.keyword, "keyword") } @Test - fun boardViewBoard_updateIsFestival_updateIsCorrect() { + fun boardViewModel_updateIsFestival_updateIsCorrect() { viewModel.updateIsFestival(1) assertEquals(viewModel.boardUiState.value.isFestival, 1) } @Test - fun boardViewBoard_updateFilterStartDate_updateIsCorrect() { + fun boardViewModel_updateFilterStartDate_updateIsCorrect() { viewModel.updateFilterStartDate("2023-12-25") assertEquals(viewModel.boardUiState.value.startDate, "2023-12-25") } @Test - fun boardViewBoard_updateFilterEndDate_updateIsCorrect() { + fun boardViewModel_updateFilterEndDate_updateIsCorrect() { viewModel.updateFilterEndDate("2023-12-31") - assertEquals(viewModel.boardUiState.value.endDate, "2023-12-31") + assertEquals("2023-12-31", viewModel.boardUiState.value.endDate) } @Test - fun boardViewBoard_updateFilterInitialState_initialStateIsFalse() { - viewModel.updateFilterInitialState() - assertFalse(viewModel.boardUiState.value.initialState) - } - - @Test - fun boardViewBoard_resetFilterInitialState_initialStateIsTrue() { - viewModel.updateFilterInitialState() - viewModel.resetFilterInitialState() - assertTrue(viewModel.boardUiState.value.initialState) + fun boardViewModel_savePreviousFilter_cancelFilter_logicIsCorrect() { + // Test only for savePreviousFilter is private test, so not test independently + viewModel.updateIsFestival(1) + viewModel.updateFilterStartDate("2023-12-25") + viewModel.savePreviousFilter() + viewModel.updateKeyword("foo") + viewModel.updateFilterStartDate("2022-01-01") + viewModel.updateFilterEndDate("2023-12-31") + viewModel.cancelFilter() + assertEquals( + BoardUiState(startDate = "2023-12-25", isFestival = 1), + viewModel.boardUiState.value + ) } @Test - fun boardViewBoard_resetBoardUiState_resetIsCorrect() { + fun boardViewModel_resetFilter_resetIsCorrect() { + viewModel.saveToken("token") + viewModel.updateKeyword("keyword") + viewModel.updateIsFestival(1) + viewModel.updateFilterStartDate("2023-12-25") + viewModel.updateFilterEndDate("2023-12-31") + viewModel.resetFilter() + assertEquals( + BoardUiState( + token = "Token token", + keyword = "keyword", + isFestival = 2, + startDate = "", + endDate = "", + initialState = false + ), + viewModel.boardUiState.value + ) + } + + @Test + fun boardViewModel_resetBoardUiState_resetIsCorrect() { viewModel.updateKeyword("keyword") viewModel.resetBoardUiState() assertEquals(viewModel.boardUiState.value, BoardUiState()) } @Test - fun boardViewBoard_updatePostStartDate_updateIsCorrect() { + fun boardViewModel_updatePostStartDate_updateIsCorrect() { viewModel.updatePostStartDate("2023-12-25") assertEquals(viewModel.boardPostUiState.value.startDate, "2023-12-25") } @Test - fun boardViewBoard_updatePostEndDate_updateIsCorrect() { + fun boardViewModel_updatePostEndDate_updateIsCorrect() { viewModel.updatePostEndDate("2023-12-31") assertEquals(viewModel.boardPostUiState.value.endDate, "2023-12-31") } @Test - fun boardViewBoard_resetBoardPostUiState_updateIsCorrect() { + fun boardViewModel_resetBoardPostUiState_updateIsCorrect() { viewModel.updatePostStartDate("2023-12-25") viewModel.resetBoardPostUiState() assertEquals(viewModel.boardPostUiState.value, BoardPostUiState())