diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 6c7528d49..eae55974c 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -44,8 +44,9 @@ dependencies { // Kotlin implementation(libs.kotlin) - // Lifecycle Ktx + // AndroidXDependencies implementation(libs.androidx.lifecycle.runtime.ktx) + implementation(libs.androidx.compose.saveable) // Hilt implementation(libs.hilt.android) diff --git a/core/src/main/java/com/terning/core/designsystem/component/bottomsheet/TerningBasicBottomSheet.kt b/core/src/main/java/com/terning/core/designsystem/component/bottomsheet/TerningBasicBottomSheet.kt new file mode 100644 index 000000000..c922054a6 --- /dev/null +++ b/core/src/main/java/com/terning/core/designsystem/component/bottomsheet/TerningBasicBottomSheet.kt @@ -0,0 +1,28 @@ +package com.terning.core.designsystem.component.bottomsheet + +import androidx.compose.foundation.layout.navigationBarsPadding +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.ModalBottomSheet +import androidx.compose.material3.rememberModalBottomSheetState +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun TerningBasicBottomSheet( + modifier: Modifier = Modifier, + content: @Composable () -> Unit, + onDismissRequest: () -> Unit +) { + val sheetState = rememberModalBottomSheetState() + + ModalBottomSheet( + onDismissRequest = { + onDismissRequest() + }, + sheetState = sheetState, + modifier = modifier.navigationBarsPadding() + ) { + content() + } +} \ No newline at end of file diff --git a/core/src/main/java/com/terning/core/designsystem/component/box/ScrapBox.kt b/core/src/main/java/com/terning/core/designsystem/component/box/ScrapBox.kt new file mode 100644 index 000000000..03c6eb7f7 --- /dev/null +++ b/core/src/main/java/com/terning/core/designsystem/component/box/ScrapBox.kt @@ -0,0 +1,103 @@ +package com.terning.core.designsystem.component.box + +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +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.width +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.shadow +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp +import com.terning.core.designsystem.theme.CalPink +import com.terning.core.designsystem.theme.CalPurple +import com.terning.core.designsystem.theme.Grey150 +import com.terning.core.designsystem.theme.White + +/** + * ScrapBox is made for easy customization of scrap box used in Calendar & Home Screen + * + * [modifier] must be assigned for assigning size of the box and padding + * [elevation] must be set greater than zero for shadow effect, mainly used in Calendar + * [borderWidth] must be set greater than zero for border effect, mainly used in Home + */ + +@Composable +fun ScrapBox( + cornerRadius: Dp, + scrapColor: Color, + modifier: Modifier = Modifier, + elevation: Dp = 0.dp, + borderWidth: Dp = 0.dp, + borderColor: Color = Grey150, + content: @Composable () -> Unit, +) { + Box( + modifier = modifier + .border( + width = borderWidth, + color = borderColor, + RoundedCornerShape(cornerRadius), + ) + .shadow( + elevation = elevation, + RoundedCornerShape(cornerRadius), + ) + ) { + Box( + modifier = Modifier + .background( + color = scrapColor, + shape = RoundedCornerShape(cornerRadius) + ) + .fillMaxSize() + ) + Box( + modifier = Modifier + .fillMaxSize() + .padding(start = 9.dp) + .background( + shape = RoundedCornerShape( + topEnd = cornerRadius, bottomEnd = cornerRadius + ), color = White + ) + ) { + content() + } + } +} + +@Preview(showBackground = true) +@Composable +fun BorderedScrapBoxPreview() { + ScrapBox( + modifier = Modifier + .height(116.dp) + .width(140.dp), + scrapColor = CalPink, + cornerRadius = 5.dp, + borderWidth = 1.dp + ) {} +} + +@Preview(showBackground = true) +@Composable +fun ShadowedScrapBoxPreview() { + ScrapBox( + modifier = Modifier + .height(height = 92.dp) + .fillMaxWidth(), + scrapColor = CalPurple, + cornerRadius = 10.dp, + elevation = 1.dp + ) {} +} \ No newline at end of file diff --git a/core/src/main/java/com/terning/core/designsystem/component/button/TerningBasicButton.kt b/core/src/main/java/com/terning/core/designsystem/component/button/TerningBasicButton.kt index 4da897a1d..ed923e9bd 100644 --- a/core/src/main/java/com/terning/core/designsystem/component/button/TerningBasicButton.kt +++ b/core/src/main/java/com/terning/core/designsystem/component/button/TerningBasicButton.kt @@ -3,6 +3,7 @@ package com.terning.core.designsystem.component.button import androidx.annotation.StringRes import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.interaction.collectIsPressedAsState +import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.material.ripple.LocalRippleTheme @@ -46,6 +47,7 @@ fun TerningBasicButton( CompositionLocalProvider(LocalRippleTheme provides NoRippleTheme) { Button( + contentPadding = PaddingValues(paddingVertical), modifier = modifier.fillMaxWidth(), interactionSource = interactionSource, enabled = isEnabled, @@ -61,7 +63,6 @@ fun TerningBasicButton( Text( text = stringResource(id = text), style = style, - modifier = modifier.padding(vertical = paddingVertical) ) } } diff --git a/core/src/main/java/com/terning/core/designsystem/component/textfield/SearchTextField.kt b/core/src/main/java/com/terning/core/designsystem/component/textfield/SearchTextField.kt index bc065431e..29dc5cf87 100644 --- a/core/src/main/java/com/terning/core/designsystem/component/textfield/SearchTextField.kt +++ b/core/src/main/java/com/terning/core/designsystem/component/textfield/SearchTextField.kt @@ -4,6 +4,7 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.graphics.SolidColor import com.terning.core.designsystem.theme.Grey300 import com.terning.core.designsystem.theme.Grey400 +import com.terning.core.designsystem.theme.TerningMain import com.terning.core.designsystem.theme.TerningTheme @Composable @@ -12,6 +13,7 @@ fun SearchTextField( onValueChange: (String) -> Unit, hint: String, leftIcon: Int, + readOnly: Boolean = false, ) { TerningBasicTextField( value = text, @@ -19,11 +21,12 @@ fun SearchTextField( textStyle = TerningTheme.typography.button3, textColor = Grey400, cursorBrush = SolidColor(Grey300), - drawLineColor = Grey300, + drawLineColor = TerningMain, strokeWidth = 2f, hint = hint, hintColor = Grey300, leftIcon = leftIcon, - leftIconColor = Grey400, + leftIconColor = TerningMain, + readOnly = readOnly, ) } \ No newline at end of file diff --git a/core/src/main/java/com/terning/core/designsystem/component/textfield/TerningBasicTextField.kt b/core/src/main/java/com/terning/core/designsystem/component/textfield/TerningBasicTextField.kt index 358e42b5a..a9045ef5e 100644 --- a/core/src/main/java/com/terning/core/designsystem/component/textfield/TerningBasicTextField.kt +++ b/core/src/main/java/com/terning/core/designsystem/component/textfield/TerningBasicTextField.kt @@ -37,7 +37,6 @@ import com.terning.core.designsystem.theme.White fun TerningBasicTextField( value: String, onValueChange: (String) -> Unit, - readOnly: Boolean = false, textStyle: TextStyle, textColor: Color, hintColor: Color, @@ -52,6 +51,7 @@ fun TerningBasicTextField( helperMessage: String = "", helperIcon: Int? = null, helperColor: Color = TerningMain, + readOnly: Boolean = false, ) { val keyboardController = LocalSoftwareKeyboardController.current val focusManager = LocalFocusManager.current @@ -62,7 +62,6 @@ fun TerningBasicTextField( onValueChange = onValueChange, singleLine = true, maxLines = 1, - readOnly = readOnly, keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done), keyboardActions = KeyboardActions( onDone = { @@ -124,7 +123,9 @@ fun TerningBasicTextField( ) } } - }) + }, + readOnly = readOnly, + ) Row( verticalAlignment = Alignment.CenterVertically, diff --git a/core/src/main/java/com/terning/core/designsystem/component/topappbar/TerningBasicTopAppBar.kt b/core/src/main/java/com/terning/core/designsystem/component/topappbar/TerningBasicTopAppBar.kt index 1f54bb766..a5088099f 100644 --- a/core/src/main/java/com/terning/core/designsystem/component/topappbar/TerningBasicTopAppBar.kt +++ b/core/src/main/java/com/terning/core/designsystem/component/topappbar/TerningBasicTopAppBar.kt @@ -1,16 +1,21 @@ package com.terning.core.designsystem.component.topappbar +import androidx.compose.foundation.layout.padding import androidx.compose.material3.CenterAlignedTopAppBar import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp import com.terning.core.R import com.terning.core.designsystem.theme.TerningTheme +import com.terning.core.designsystem.theme.White @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -49,5 +54,7 @@ fun TerningBasicTopAppBar( action() } }, + colors = TopAppBarDefaults.topAppBarColors(White), + modifier = Modifier.padding(horizontal = 16.dp) ) } \ No newline at end of file diff --git a/core/src/main/java/com/terning/core/designsystem/theme/Color.kt b/core/src/main/java/com/terning/core/designsystem/theme/Color.kt index 0a5bfcab0..e9ed4d1be 100644 --- a/core/src/main/java/com/terning/core/designsystem/theme/Color.kt +++ b/core/src/main/java/com/terning/core/designsystem/theme/Color.kt @@ -17,22 +17,27 @@ val Black = Color(0xFF171717) val TerningMain = Color(0xFF1EA65E) val TerningMain2 = Color(0xFF179653) +// Sub Color +val TerningSub1 = Color(0xFF179653) +val TerningSub2 = Color(0xFF52C689) +val TerningSub3 = Color(0XFFE2F1E9) +val TerningSub4 = Color(0XFFE9F8F0) +val TerningSub5 = Color(0XFFF8FFFB) + +// Background +val Back = Color(0xFFF8F8F8) +val ToastGrey = Color(0XFF666666) + // Calendar Color val CalRed = Color(0xFFED4E54) - val CalOrange1 = Color(0xFFEE7647) val CalOrange2 = Color(0xFF5397F3) - val CalYellow = Color(0xFFF5E660) - val CalGreen1 = Color(0xFFC4E953) val CalGreen2 = Color(0xFF84D558) - val CalBlue1 = Color(0xFF45D0CC) val CalBlue2 = Color(0xFF4119F2) - val CalPurple = Color(0xFF9B64E2) - val CalPink = Color(0xFFF260AC) // Other diff --git a/core/src/main/java/com/terning/core/designsystem/theme/Theme.kt b/core/src/main/java/com/terning/core/designsystem/theme/Theme.kt index e7bea86a3..3c37a431e 100644 --- a/core/src/main/java/com/terning/core/designsystem/theme/Theme.kt +++ b/core/src/main/java/com/terning/core/designsystem/theme/Theme.kt @@ -10,6 +10,7 @@ import androidx.compose.runtime.staticCompositionLocalOf private val LightColorScheme = lightColorScheme( primary = TerningMain, + background = White ) private val LocalTerningTypography = staticCompositionLocalOf<TerningTypography> { diff --git a/core/src/main/java/com/terning/core/extension/LocalDateExt.kt b/core/src/main/java/com/terning/core/extension/LocalDateExt.kt index edcf61c96..ee8c97476 100644 --- a/core/src/main/java/com/terning/core/extension/LocalDateExt.kt +++ b/core/src/main/java/com/terning/core/extension/LocalDateExt.kt @@ -3,4 +3,8 @@ package com.terning.core.extension import java.time.LocalDate fun LocalDate.getStringAsTitle(): String = - "${year}년 ${monthValue.toString().padStart(2, '0')}월" \ No newline at end of file + "${year}년 ${monthValue.toString().padStart(2, '0')}월" + +fun LocalDate.getWeekIndexContainingSelectedDate(): Int = dayOfMonth / 7 + +fun LocalDate.isToday(): Boolean = this == LocalDate.now() \ No newline at end of file diff --git a/data/src/main/java/com/terning/data/dto/BaseResponse.kt b/data/src/main/java/com/terning/data/dto/BaseResponse.kt index 0de489ff1..a47d7bce9 100644 --- a/data/src/main/java/com/terning/data/dto/BaseResponse.kt +++ b/data/src/main/java/com/terning/data/dto/BaseResponse.kt @@ -7,10 +7,8 @@ import kotlinx.serialization.Serializable data class BaseResponse<T>( @SerialName("status") val status: Int, - @SerialName("code") - val code: String, @SerialName("message") val message: String, - @SerialName("data") - val data: T, + @SerialName("result") + val result: T, ) diff --git a/feature/build.gradle.kts b/feature/build.gradle.kts index 16da9b5ee..372c480bb 100644 --- a/feature/build.gradle.kts +++ b/feature/build.gradle.kts @@ -69,6 +69,7 @@ dependencies { implementation(libs.androidx.workManager) implementation(libs.hilt.compiler) implementation(libs.androidx.lifecycle.runtime.compose.android) + implementation(libs.androidx.compose.saveable) // KspDependencies ksp(libs.hilt.android.compiler) diff --git a/feature/src/main/java/com/terning/feature/calendar/CalendarMonth.kt b/feature/src/main/java/com/terning/feature/calendar/CalendarMonth.kt index ef34392fa..fc9636da3 100644 --- a/feature/src/main/java/com/terning/feature/calendar/CalendarMonth.kt +++ b/feature/src/main/java/com/terning/feature/calendar/CalendarMonth.kt @@ -15,9 +15,10 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.terning.core.designsystem.theme.Grey150 import com.terning.core.designsystem.theme.TerningPointTheme -import com.terning.core.designsystem.theme.TerningTheme +import com.terning.core.extension.isToday import com.terning.feature.calendar.models.MonthData import com.terning.feature.calendar.models.Scrap +import com.terning.feature.calendar.models.SelectedDateState import java.time.LocalDate import java.time.YearMonth @@ -26,7 +27,7 @@ fun CalendarMonth( modifier: Modifier = Modifier, monthData: MonthData, onDateSelected: (LocalDate) -> Unit, - selectedDate: LocalDate, + selectedDate: SelectedDateState, scrapLists: List<List<Scrap>> = listOf() ) { Column( @@ -48,8 +49,8 @@ fun CalendarMonth( ) { CalendarDay( dayData = day, - isSelected = selectedDate == day.date, - isToday = day.date == LocalDate.now(), + isSelected = selectedDate.selectedDate == day.date && selectedDate.isEnabled, + isToday = day.date.isToday(), onDateSelected = onDateSelected ) if(!day.isOutDate) { @@ -79,7 +80,7 @@ fun CalendarMonthPreview() { TerningPointTheme { CalendarMonth( monthData = MonthData(YearMonth.now()), - selectedDate = LocalDate.now(), + selectedDate = SelectedDateState(LocalDate.now(), true), onDateSelected = {}, scrapLists = listOf() ) diff --git a/feature/src/main/java/com/terning/feature/calendar/CalendarMonths.kt b/feature/src/main/java/com/terning/feature/calendar/CalendarMonths.kt index 4f179af8d..5d4ecc101 100644 --- a/feature/src/main/java/com/terning/feature/calendar/CalendarMonths.kt +++ b/feature/src/main/java/com/terning/feature/calendar/CalendarMonths.kt @@ -1,7 +1,6 @@ package com.terning.feature.calendar import androidx.compose.foundation.background -import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.lazy.LazyListState import androidx.compose.foundation.lazy.LazyRow import androidx.compose.runtime.Composable @@ -11,17 +10,18 @@ import com.terning.feature.calendar.models.CalendarDefaults.flingBehavior import com.terning.feature.calendar.models.CalendarState.Companion.getDateByPage import com.terning.feature.calendar.models.MonthData import com.terning.feature.calendar.models.Scrap +import com.terning.feature.calendar.models.SelectedDateState import java.time.LocalDate import java.time.YearMonth @Composable fun CalendarMonths( - modifier: Modifier = Modifier, listState: LazyListState, onDateSelected: (LocalDate) -> Unit, pages: Int, - selectedDate: LocalDate, - scrapLists: List<List<Scrap>> + selectedDate: SelectedDateState, + scrapLists: List<List<Scrap>>, + modifier: Modifier = Modifier, ) { LazyRow( modifier = modifier diff --git a/feature/src/main/java/com/terning/feature/calendar/CalendarRoute.kt b/feature/src/main/java/com/terning/feature/calendar/CalendarRoute.kt index c706c5715..827f8d416 100644 --- a/feature/src/main/java/com/terning/feature/calendar/CalendarRoute.kt +++ b/feature/src/main/java/com/terning/feature/calendar/CalendarRoute.kt @@ -1,6 +1,11 @@ package com.terning.feature.calendar import androidx.activity.compose.BackHandler +import androidx.compose.animation.AnimatedContent +import androidx.compose.animation.SizeTransform +import androidx.compose.animation.slideInVertically +import androidx.compose.animation.slideOutVertically +import androidx.compose.animation.togetherWith import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer @@ -21,14 +26,18 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.terning.core.designsystem.theme.Grey200 +import com.terning.feature.R import com.terning.feature.calendar.component.CalendarTopBar import com.terning.feature.calendar.component.WeekDaysHeader import com.terning.feature.calendar.models.CalendarState import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.launch +import java.time.LocalDate @Composable fun CalendarRoute() { @@ -40,35 +49,33 @@ fun CalendarScreen( modifier: Modifier = Modifier, viewModel: CalendarViewModel = hiltViewModel() ) { - val selectedDate by viewModel.selectedDate.collectAsState() - val state by remember{ mutableStateOf(CalendarState()) } + val selectedDate by viewModel.selectedDate.collectAsStateWithLifecycle() + val state by remember { mutableStateOf(CalendarState()) } val listState = rememberLazyListState( initialFirstVisibleItemIndex = state.getInitialPage() ) - var currentDate by remember { mutableStateOf(selectedDate) } - var currentPage by remember { mutableIntStateOf(listState.firstVisibleItemIndex)} + var currentDate by remember { mutableStateOf(LocalDate.now()) } + var currentPage by remember { mutableIntStateOf(listState.firstVisibleItemIndex) } var isListExpanded by remember { mutableStateOf(false) } - var isWeekEnabled by remember { mutableStateOf(false) } LaunchedEffect(key1 = listState) { snapshotFlow { listState.firstVisibleItemIndex } .distinctUntilChanged() - .collect{ - val swipeDirection = (listState.firstVisibleItemIndex - currentPage).coerceIn(-1, 1).toLong() + .collect { + val swipeDirection = + (listState.firstVisibleItemIndex - currentPage).coerceIn(-1, 1).toLong() currentDate = currentDate.plusMonths(swipeDirection) currentPage = listState.firstVisibleItemIndex } } - LaunchedEffect(key1 = selectedDate) { - isWeekEnabled = true - } - BackHandler { - isWeekEnabled = false + if (selectedDate.isEnabled) { + viewModel.updateSelectedDate(selectedDate.selectedDate) + } } Scaffold( @@ -91,26 +98,57 @@ fun CalendarScreen( ) { paddingValues -> Column( modifier = Modifier - .fillMaxWidth() + .fillMaxSize() .padding(top = paddingValues.calculateTopPadding()) ) { WeekDaysHeader() - Spacer(modifier = Modifier - .fillMaxWidth() - .height(1.dp) - .background(color = Grey200) + Spacer( + modifier = Modifier + .fillMaxWidth() + .height(1.dp) + .background(color = Grey200) ) - CalendarMonths( - modifier = Modifier.fillMaxSize(), - selectedDate = selectedDate, - onDateSelected = { - viewModel.updateSelectedDate(it) + + AnimatedContent( + targetState = selectedDate.isEnabled, + transitionSpec = { + if (!targetState) { + slideInVertically { fullHeight -> -fullHeight } togetherWith + slideOutVertically { fullHeight -> fullHeight } + } else { + slideInVertically { fullHeight -> fullHeight } togetherWith + slideOutVertically { fullHeight -> -fullHeight } + }.using( + sizeTransform = SizeTransform(clip = true) + ) }, - listState = listState, - pages = state.getPageCount(), - scrapLists = viewModel.mockScrapList - ) + label = stringResource(id = R.string.calendar_animation_label) + ) { targetState -> + if (!targetState) { + CalendarMonths( + modifier = Modifier.fillMaxSize(), + selectedDate = selectedDate, + onDateSelected = { + viewModel.updateSelectedDate(it) + }, + listState = listState, + pages = state.getPageCount(), + scrapLists = viewModel.mockScrapList, + ) + } else { + CalendarWeekWithScrap( + modifier = Modifier + .fillMaxSize(), + selectedDate = selectedDate, + scrapLists = viewModel.mockScrapList, + onDateSelected = { + viewModel.updateSelectedDate(it) + } + ) + } + } } - } } + + diff --git a/feature/src/main/java/com/terning/feature/calendar/CalendarViewModel.kt b/feature/src/main/java/com/terning/feature/calendar/CalendarViewModel.kt index d57863782..6a286807b 100644 --- a/feature/src/main/java/com/terning/feature/calendar/CalendarViewModel.kt +++ b/feature/src/main/java/com/terning/feature/calendar/CalendarViewModel.kt @@ -10,6 +10,7 @@ import com.terning.core.designsystem.theme.CalPurple import com.terning.core.designsystem.theme.CalRed import com.terning.core.designsystem.theme.CalYellow import com.terning.feature.calendar.models.Scrap +import com.terning.feature.calendar.models.SelectedDateState import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow @@ -21,12 +22,29 @@ import javax.inject.Inject @HiltViewModel class CalendarViewModel @Inject constructor( ) : ViewModel() { - private val _selectedDate = MutableStateFlow<LocalDate>(LocalDate.now()) + private val _selectedDate = MutableStateFlow<SelectedDateState>( + SelectedDateState( + selectedDate = LocalDate.now(), + isEnabled = false + ) + ) val selectedDate get() = _selectedDate.asStateFlow() fun updateSelectedDate(date: LocalDate) = viewModelScope.launch { - if (_selectedDate.value != date) { - _selectedDate.value = date + if (_selectedDate.value.selectedDate != date) { + _selectedDate.update { currentState -> + currentState.copy( + selectedDate = date, + isEnabled = true + ) + } + } else { + _selectedDate.update { currentState -> + currentState.copy( + selectedDate = date, + isEnabled = !_selectedDate.value.isEnabled + ) + } } } @@ -61,18 +79,21 @@ class CalendarViewModel @Inject constructor( ) ) } + 3 -> { list.add( i, listOf() ) } + 4 -> { list.add( i, listOf() ) } + 5 -> { list.add( i, diff --git a/feature/src/main/java/com/terning/feature/calendar/CalendarWeek.kt b/feature/src/main/java/com/terning/feature/calendar/CalendarWeek.kt new file mode 100644 index 000000000..7fb0e5d43 --- /dev/null +++ b/feature/src/main/java/com/terning/feature/calendar/CalendarWeek.kt @@ -0,0 +1,54 @@ +package com.terning.feature.calendar + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyRow +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.pager.HorizontalPager +import androidx.compose.foundation.pager.rememberPagerState +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import com.terning.core.extension.getWeekIndexContainingSelectedDate +import com.terning.core.extension.isToday +import com.terning.feature.calendar.models.MonthData +import com.terning.feature.calendar.models.SelectedDateState +import java.time.LocalDate +import java.time.YearMonth + +@Composable +fun CalendarWeek( + modifier: Modifier = Modifier, + selectedDate: SelectedDateState, + onDateSelected: (LocalDate) -> Unit = {} +) { + val date = selectedDate.selectedDate + val monthData = MonthData(YearMonth.of(date.year, date.monthValue)) + val currentWeek = date.getWeekIndexContainingSelectedDate() + + val pagerState = rememberPagerState ( + initialPage = currentWeek, + pageCount = {monthData.totalDays / 7} + ) + + HorizontalPager( + modifier = modifier, + state = pagerState) { page -> + LazyRow( + modifier = Modifier + .fillMaxWidth() + .padding(20.dp), + horizontalArrangement = Arrangement.SpaceBetween + ) { + items(items = monthData.calendarMonth.weekDays[page]) { day -> + CalendarDay( + dayData = day, + isSelected = selectedDate.selectedDate == day.date && selectedDate.isEnabled, + isToday = day.date.isToday(), + onDateSelected = onDateSelected + ) + } + } + } +} \ No newline at end of file diff --git a/feature/src/main/java/com/terning/feature/calendar/CalendarWeekWithScrap.kt b/feature/src/main/java/com/terning/feature/calendar/CalendarWeekWithScrap.kt new file mode 100644 index 000000000..fbdf774cc --- /dev/null +++ b/feature/src/main/java/com/terning/feature/calendar/CalendarWeekWithScrap.kt @@ -0,0 +1,63 @@ +package com.terning.feature.calendar + +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Card +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.shadow +import androidx.compose.ui.unit.dp +import com.terning.core.designsystem.theme.Grey200 +import com.terning.core.designsystem.theme.White +import com.terning.feature.calendar.models.Scrap +import com.terning.feature.calendar.models.SelectedDateState +import java.time.LocalDate + +@Composable +fun CalendarWeekWithScrap( + modifier: Modifier = Modifier, + selectedDate: SelectedDateState, + scrapLists: List<List<Scrap>> = listOf(), + onDateSelected: (LocalDate) -> Unit +) { + Column( + modifier = modifier + ) { + Card( + modifier = Modifier + .border( + width = 0.dp, + color = Grey200, + shape = RoundedCornerShape(bottomStart = 20.dp, bottomEnd = 20.dp)) + .shadow( + shape = RoundedCornerShape(bottomStart = 20.dp, bottomEnd = 20.dp), + elevation = 1.dp + ), + + shape = RoundedCornerShape(bottomStart = 20.dp, bottomEnd = 20.dp), + ) { + CalendarWeek( + modifier = Modifier + .fillMaxWidth() + .background(White), + selectedDate = selectedDate, + onDateSelected = onDateSelected + ) + } + + LazyColumn( + modifier = Modifier + .fillMaxWidth() + ) { + /*items(items = scrapLists[selectedDate?.dayOfMonth - 1]) { + + }*/ + + } + } + +} \ No newline at end of file diff --git a/feature/src/main/java/com/terning/feature/calendar/models/SelectedDateState.kt b/feature/src/main/java/com/terning/feature/calendar/models/SelectedDateState.kt new file mode 100644 index 000000000..04864c848 --- /dev/null +++ b/feature/src/main/java/com/terning/feature/calendar/models/SelectedDateState.kt @@ -0,0 +1,8 @@ +package com.terning.feature.calendar.models + +import java.time.LocalDate + +data class SelectedDateState( + val selectedDate: LocalDate, + val isEnabled: Boolean +) diff --git a/feature/src/main/java/com/terning/feature/main/MainNavigator.kt b/feature/src/main/java/com/terning/feature/main/MainNavigator.kt index beb7b7920..68d33fb38 100644 --- a/feature/src/main/java/com/terning/feature/main/MainNavigator.kt +++ b/feature/src/main/java/com/terning/feature/main/MainNavigator.kt @@ -13,6 +13,7 @@ import com.terning.feature.calendar.navigation.navigateCalendar import com.terning.feature.home.navigation.navigateHome import com.terning.feature.mypage.navigation.navigateMyPage import com.terning.feature.onboarding.signin.navigation.SignIn +import com.terning.feature.search.navigation.Search import com.terning.feature.search.navigation.navigateSearch class MainNavigator( diff --git a/feature/src/main/java/com/terning/feature/onboarding/signin/SignInRoute.kt b/feature/src/main/java/com/terning/feature/onboarding/signin/SignInRoute.kt index 24be49cee..c1c6a22c7 100644 --- a/feature/src/main/java/com/terning/feature/onboarding/signin/SignInRoute.kt +++ b/feature/src/main/java/com/terning/feature/onboarding/signin/SignInRoute.kt @@ -56,6 +56,7 @@ fun SignInScreen( modifier: Modifier = Modifier, onSignInClick: () -> Unit = {}, ) { + Column( modifier = modifier .wrapContentHeight() @@ -70,7 +71,9 @@ fun SignInScreen( ) KakaoButton( title = stringResource(id = R.string.sign_in_kakao_button), - onSignInClick = { onSignInClick() }, + onSignInClick = { + onSignInClick() + }, modifier = modifier.padding(horizontal = 20.dp) ) } diff --git a/feature/src/main/java/com/terning/feature/onboarding/signup/SignUpViewModel.kt b/feature/src/main/java/com/terning/feature/onboarding/signup/SignUpViewModel.kt new file mode 100644 index 000000000..b0778653a --- /dev/null +++ b/feature/src/main/java/com/terning/feature/onboarding/signup/SignUpViewModel.kt @@ -0,0 +1,10 @@ +package com.terning.feature.onboarding.signup + +import androidx.lifecycle.ViewModel +import dagger.hilt.android.lifecycle.HiltViewModel +import javax.inject.Inject + +@HiltViewModel +class SignUpViewModel @Inject constructor() : ViewModel(){ + +} \ No newline at end of file diff --git a/feature/src/main/java/com/terning/feature/onboarding/signup/component/SignUpBottomSheet.kt b/feature/src/main/java/com/terning/feature/onboarding/signup/component/SignUpBottomSheet.kt new file mode 100644 index 000000000..1cd62a4be --- /dev/null +++ b/feature/src/main/java/com/terning/feature/onboarding/signup/component/SignUpBottomSheet.kt @@ -0,0 +1,100 @@ +package com.terning.feature.onboarding.signup.component + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.aspectRatio +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.grid.GridCells +import androidx.compose.foundation.lazy.grid.LazyVerticalGrid +import androidx.compose.foundation.lazy.grid.items +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.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import com.terning.core.designsystem.component.bottomsheet.TerningBasicBottomSheet +import com.terning.core.designsystem.component.button.RoundButton +import com.terning.core.designsystem.theme.TerningTheme +import com.terning.core.extension.noRippleClickable +import com.terning.feature.R + +@Composable +fun SignUpBottomSheet( + modifier: Modifier = Modifier, + onDismiss: () -> Unit, + onStartDialog: () -> Unit +) { + TerningBasicBottomSheet( + content = { + Column { + Text( + text = stringResource(id = R.string.sign_up_bottom_sheet_title), + style = TerningTheme.typography.title2, + modifier = modifier + .padding( + start = 28.dp, + bottom = 25.dp + ), + ) + RadioButtonGroup() + Spacer(modifier = modifier.padding(bottom = 24.dp)) + RoundButton( + style = TerningTheme.typography.button0, + paddingVertical = 19.dp, + cornerRadius = 10.dp, + text = R.string.sign_up_dialog_start, + onButtonClick = { onStartDialog() }, + modifier = modifier.padding(horizontal = 24.dp) + ) + Spacer(modifier = modifier.padding(bottom = 15.dp)) + } + }, + onDismissRequest = { onDismiss() } + ) +} + +@Composable +fun RadioButtonGroup( + modifier: Modifier = Modifier +) { + val options = listOf( + R.drawable.ic_character1, + R.drawable.ic_character2, + R.drawable.ic_character3, + R.drawable.ic_character4, + R.drawable.ic_character5, + R.drawable.ic_character6 + ) + + var selectedOption by rememberSaveable { mutableIntStateOf(options[0]) } + + LazyVerticalGrid( + columns = GridCells.Fixed(3), + verticalArrangement = Arrangement.spacedBy(20.dp), + horizontalArrangement = Arrangement.spacedBy(24.dp), + modifier = modifier + .padding(horizontal = 42.dp) + ) { + items(options) { option -> + Image( + painter = painterResource( + id = if (option == selectedOption) R.drawable.ic_selected_character + else option + ), + contentDescription = stringResource(id = R.string.sign_up_bottom_sheet_description), + modifier = modifier + .aspectRatio(1f) + .noRippleClickable { + selectedOption = option + } + ) + } + } +} diff --git a/feature/src/main/java/com/terning/feature/search/SearchRoute.kt b/feature/src/main/java/com/terning/feature/search/SearchRoute.kt index 90701416c..dc075791f 100644 --- a/feature/src/main/java/com/terning/feature/search/SearchRoute.kt +++ b/feature/src/main/java/com/terning/feature/search/SearchRoute.kt @@ -1,8 +1,12 @@ package com.terning.feature.search +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -11,12 +15,14 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp -import com.terning.core.designsystem.component.textfield.NameTextField import com.terning.core.designsystem.component.textfield.SearchTextField -import com.terning.core.designsystem.theme.Grey400 -import com.terning.core.designsystem.theme.TerningMain -import com.terning.core.designsystem.theme.WarningRed +import com.terning.core.designsystem.theme.Black +import com.terning.core.designsystem.theme.Grey100 +import com.terning.core.designsystem.theme.TerningTheme import com.terning.feature.R +import com.terning.feature.search.component.ImageSlider +import com.terning.feature.search.component.InternListType +import com.terning.feature.search.component.SearchInternList @Composable fun SearchRoute() { @@ -26,61 +32,55 @@ fun SearchRoute() { @Composable fun SearchScreen() { var text by remember { mutableStateOf("") } - - // TODO 프로필 스크린 TextField로, 삭제될 코드입니다 - var helperMessage by remember { mutableStateOf(R.string.profile_text_field_helper) } - var helperIcon by remember { mutableStateOf<Int?>(null) } - var helperColor by remember { mutableStateOf(Grey400) } - val specialCharacterPattern = Regex("[!@#\$%^&*(),.?\":{}|<>\\[\\]\\\\/]") - - // TODO 프로필 스크린 TextField로, 삭제될 코드입니다 - fun updateHelper(text: String) { - helperMessage = when { - text.isEmpty() -> R.string.profile_text_field_helper - specialCharacterPattern.containsMatchIn(text) -> R.string.profile_text_field_warning - text.length <= 12 -> R.string.profile_text_field_check - else -> R.string.profile_text_field_helper - } - helperIcon = when { - text.isEmpty() -> null - specialCharacterPattern.containsMatchIn(text) -> R.drawable.ic_warning - text.length <= 12 -> R.drawable.ic_check - else -> null - } - helperColor = when { - text.isEmpty() -> Grey400 - specialCharacterPattern.containsMatchIn(text) -> WarningRed - text.length <= 12 -> TerningMain - else -> Grey400 - } - } + val images = listOf( + R.drawable.ic_nav_search, + R.drawable.ic_check, + R.drawable.ic_nav_my_page, + ) Column( modifier = Modifier .fillMaxWidth() - .padding(horizontal = 16.dp) ) { + Box( + modifier = Modifier.padding( + horizontal = 24.dp, + vertical = 16.dp + ) + ) { + SearchTextField( + text = text, + onValueChange = { newText -> + text = newText + }, + hint = stringResource(R.string.search_text_field_hint), + leftIcon = R.drawable.ic_nav_search, + readOnly = true, + ) + } - SearchTextField( - text = text, - onValueChange = { newText -> - text = newText - }, - hint = stringResource(R.string.search_text_field_hint), - leftIcon = R.drawable.ic_nav_search + ImageSlider( + images = images ) - // TODO 프로필 스크린 TextField로, 삭제될 코드입니다 - NameTextField( - text = text, - onValueChange = { newText -> - text = newText - updateHelper(newText) - }, - hint = stringResource(R.string.profile_text_field_hint), - helperMessage = stringResource(helperMessage), - helperIcon = helperIcon, - helperColor = helperColor + Spacer(modifier = Modifier.padding(8.dp)) + + Text( + text = stringResource(id = R.string.search_today_popular), + modifier = Modifier.padding( + horizontal = 24.dp, + vertical = 4.dp + ), + style = TerningTheme.typography.title1, + color = Black ) + + SearchInternList(type = InternListType.VIEW) + HorizontalDivider( + thickness = 4.dp, + modifier = Modifier.padding(vertical = 8.dp), + color = Grey100, + ) + SearchInternList(type = InternListType.SCRAP) } -} +} \ No newline at end of file diff --git a/feature/src/main/java/com/terning/feature/search/component/DotsIndicator.kt b/feature/src/main/java/com/terning/feature/search/component/DotsIndicator.kt new file mode 100644 index 000000000..908eb460e --- /dev/null +++ b/feature/src/main/java/com/terning/feature/search/component/DotsIndicator.kt @@ -0,0 +1,29 @@ +package com.terning.feature.search.component + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.padding +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp + +@Composable +fun DotsIndicator( + modifier: Modifier = Modifier, + pageCount: Int, + currentPage: Int, +) { + Row( + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.padding(8.dp) + ) { + repeat(pageCount) { index -> + IndicatorDots( + isSelected = index == currentPage, + modifier = modifier + ) + } + } +} \ No newline at end of file diff --git a/feature/src/main/java/com/terning/feature/search/component/ImageSlider.kt b/feature/src/main/java/com/terning/feature/search/component/ImageSlider.kt new file mode 100644 index 000000000..ddfb8c0bf --- /dev/null +++ b/feature/src/main/java/com/terning/feature/search/component/ImageSlider.kt @@ -0,0 +1,72 @@ +package com.terning.feature.search.component + +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.wrapContentSize +import androidx.compose.foundation.pager.HorizontalPager +import androidx.compose.foundation.pager.rememberPagerState +import androidx.compose.material3.Card +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.unit.dp +import com.terning.core.designsystem.theme.Grey200 +import kotlinx.coroutines.delay + +@Composable +fun ImageSlider( + modifier: Modifier = Modifier, + images: List<Int>, +) { + val pagerState = rememberPagerState(pageCount = { images.size }) + + LaunchedEffect(Unit) { + while (true) { + delay(3000) + val nextPage = (pagerState.currentPage + 1) % pagerState.pageCount + pagerState.scrollToPage(nextPage) + } + } + Column( + modifier + .fillMaxWidth() + .background(Grey200), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Box( + modifier = modifier + .wrapContentSize(), + contentAlignment = Alignment.BottomCenter + ) { + HorizontalPager( + state = pagerState, + modifier = modifier.wrapContentSize() + ) { currentPage -> + Card( + modifier + .wrapContentSize() + ) { + Image( + painter = painterResource(id = images[currentPage]), + contentDescription = null, + modifier = modifier + .fillMaxWidth() + .height(112.dp) + .padding(16.dp) + ) + } + } + DotsIndicator( + pageCount = images.size, + currentPage = pagerState.currentPage + ) + } + } +} \ No newline at end of file diff --git a/feature/src/main/java/com/terning/feature/search/component/IndicatorDots.kt b/feature/src/main/java/com/terning/feature/search/component/IndicatorDots.kt new file mode 100644 index 000000000..dc91d16e5 --- /dev/null +++ b/feature/src/main/java/com/terning/feature/search/component/IndicatorDots.kt @@ -0,0 +1,26 @@ +package com.terning.feature.search.component + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.unit.dp +import com.terning.core.designsystem.theme.TerningMain +import com.terning.core.designsystem.theme.White + +@Composable +fun IndicatorDots( + isSelected: Boolean, modifier: Modifier, +) { + Box( + modifier = modifier + .padding(2.dp) + .clip(CircleShape) + .size(6.dp) + .background(if (isSelected) TerningMain else White) + ) +} \ No newline at end of file diff --git a/feature/src/main/java/com/terning/feature/search/component/InternListType.kt b/feature/src/main/java/com/terning/feature/search/component/InternListType.kt new file mode 100644 index 000000000..9caae356d --- /dev/null +++ b/feature/src/main/java/com/terning/feature/search/component/InternListType.kt @@ -0,0 +1,6 @@ +package com.terning.feature.search.component + +enum class InternListType(val type: String) { + VIEW("view"), + SCRAP("scrap"); +} diff --git a/feature/src/main/java/com/terning/feature/search/component/SearchIntern.kt b/feature/src/main/java/com/terning/feature/search/component/SearchIntern.kt new file mode 100644 index 000000000..89ba2c0db --- /dev/null +++ b/feature/src/main/java/com/terning/feature/search/component/SearchIntern.kt @@ -0,0 +1,63 @@ +package com.terning.feature.search.component + +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.shadow +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.dp +import com.terning.core.designsystem.theme.Black +import com.terning.core.designsystem.theme.Grey400 +import com.terning.core.designsystem.theme.TerningTheme +import com.terning.core.designsystem.theme.White +import com.terning.feature.R + +@Composable +fun SearchIntern() { + Column( + verticalArrangement = Arrangement.spacedBy( + 10.dp, + Alignment.Top + ), + horizontalAlignment = Alignment.CenterHorizontally, + modifier = Modifier + .shadow( + elevation = 4.dp, + // TODO 효빈 그림자 PR 풀 받아서 바꾸기 + spotColor = Color(0x26DDDDDD), + ambientColor = Color(0x26DDDDDD) + ) + .background( + color = White, + shape = RoundedCornerShape(size = 5.dp) + ) + .padding(vertical = 8.dp) + ) { + Image( + painter = painterResource(id = R.drawable.ic_nav_search), + contentDescription = null, + modifier = Modifier + .fillMaxWidth() + .padding(16.dp) + .background(Grey400) + ) + Text( + text = "[유한킴벌리]\n그린캠프 w. 대학생 숲 \n활동가 모집", + modifier = Modifier.padding(horizontal = 8.dp), + style = TerningTheme.typography.body6, + color = Black, + overflow = TextOverflow.Ellipsis, + maxLines = 3 + ) + } +} \ No newline at end of file diff --git a/feature/src/main/java/com/terning/feature/search/component/SearchInternList.kt b/feature/src/main/java/com/terning/feature/search/component/SearchInternList.kt new file mode 100644 index 000000000..8c0eafa80 --- /dev/null +++ b/feature/src/main/java/com/terning/feature/search/component/SearchInternList.kt @@ -0,0 +1,41 @@ +package com.terning.feature.search.component + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyRow +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import com.terning.core.designsystem.theme.Grey400 +import com.terning.core.designsystem.theme.TerningTheme +import com.terning.feature.R + +@Composable +fun SearchInternList( + type: InternListType, +) { + Column(modifier = Modifier.padding(horizontal = 24.dp)) { + Text( + text = stringResource( + id = when (type) { + InternListType.VIEW -> R.string.search_most_view_intern + InternListType.SCRAP -> R.string.search_most_scrap_intern + } + ), + style = TerningTheme.typography.title5, + color = Grey400 + ) + + LazyRow( + modifier = Modifier.padding(vertical = 8.dp), + horizontalArrangement = Arrangement.spacedBy(12.dp), + ) { + items(5) { + SearchIntern() + } + } + } +} \ No newline at end of file diff --git a/feature/src/main/res/drawable/ic_character1.xml b/feature/src/main/res/drawable/ic_character1.xml new file mode 100644 index 000000000..e7a473ec6 --- /dev/null +++ b/feature/src/main/res/drawable/ic_character1.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="76dp" + android:height="76dp" + android:viewportWidth="76" + android:viewportHeight="76"> + <path + android:pathData="M38,38m-38,0a38,38 0,1 1,76 0a38,38 0,1 1,-76 0" + android:fillColor="#DDDDDD"/> +</vector> diff --git a/feature/src/main/res/drawable/ic_character2.xml b/feature/src/main/res/drawable/ic_character2.xml new file mode 100644 index 000000000..e7a473ec6 --- /dev/null +++ b/feature/src/main/res/drawable/ic_character2.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="76dp" + android:height="76dp" + android:viewportWidth="76" + android:viewportHeight="76"> + <path + android:pathData="M38,38m-38,0a38,38 0,1 1,76 0a38,38 0,1 1,-76 0" + android:fillColor="#DDDDDD"/> +</vector> diff --git a/feature/src/main/res/drawable/ic_character3.xml b/feature/src/main/res/drawable/ic_character3.xml new file mode 100644 index 000000000..e7a473ec6 --- /dev/null +++ b/feature/src/main/res/drawable/ic_character3.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="76dp" + android:height="76dp" + android:viewportWidth="76" + android:viewportHeight="76"> + <path + android:pathData="M38,38m-38,0a38,38 0,1 1,76 0a38,38 0,1 1,-76 0" + android:fillColor="#DDDDDD"/> +</vector> diff --git a/feature/src/main/res/drawable/ic_character4.xml b/feature/src/main/res/drawable/ic_character4.xml new file mode 100644 index 000000000..e7a473ec6 --- /dev/null +++ b/feature/src/main/res/drawable/ic_character4.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="76dp" + android:height="76dp" + android:viewportWidth="76" + android:viewportHeight="76"> + <path + android:pathData="M38,38m-38,0a38,38 0,1 1,76 0a38,38 0,1 1,-76 0" + android:fillColor="#DDDDDD"/> +</vector> diff --git a/feature/src/main/res/drawable/ic_character5.xml b/feature/src/main/res/drawable/ic_character5.xml new file mode 100644 index 000000000..e7a473ec6 --- /dev/null +++ b/feature/src/main/res/drawable/ic_character5.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="76dp" + android:height="76dp" + android:viewportWidth="76" + android:viewportHeight="76"> + <path + android:pathData="M38,38m-38,0a38,38 0,1 1,76 0a38,38 0,1 1,-76 0" + android:fillColor="#DDDDDD"/> +</vector> diff --git a/feature/src/main/res/drawable/ic_character6.xml b/feature/src/main/res/drawable/ic_character6.xml new file mode 100644 index 000000000..e7a473ec6 --- /dev/null +++ b/feature/src/main/res/drawable/ic_character6.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="76dp" + android:height="76dp" + android:viewportWidth="76" + android:viewportHeight="76"> + <path + android:pathData="M38,38m-38,0a38,38 0,1 1,76 0a38,38 0,1 1,-76 0" + android:fillColor="#DDDDDD"/> +</vector> diff --git a/feature/src/main/res/drawable/ic_selected_character.xml b/feature/src/main/res/drawable/ic_selected_character.xml new file mode 100644 index 000000000..c5d459b5f --- /dev/null +++ b/feature/src/main/res/drawable/ic_selected_character.xml @@ -0,0 +1,14 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="86dp" + android:height="86dp" + android:viewportWidth="86" + android:viewportHeight="86"> + <path + android:pathData="M43,43m-38,0a38,38 0,1 1,76 0a38,38 0,1 1,-76 0" + android:fillColor="#DDDDDD"/> + <path + android:pathData="M42.998,43m-41.533,0a41.533,41.533 0,1 1,83.067 0a41.533,41.533 0,1 1,-83.067 0" + android:strokeWidth="2" + android:fillColor="#00000000" + android:strokeColor="#1EAC61"/> +</vector> diff --git a/feature/src/main/res/values/strings.xml b/feature/src/main/res/values/strings.xml index 2247cdd3a..9594d9aa8 100644 --- a/feature/src/main/res/values/strings.xml +++ b/feature/src/main/res/values/strings.xml @@ -5,6 +5,7 @@ <string name="server_success">서버통신 성공</string> <string name="server_failure">서버통신 실패</string> + <!--bottom_navigation--> <string name="bottom_nav_home">홈</string> <string name="bottom_nav_calendar">캘린더</string> <string name="bottom_nav_search">탐색</string> @@ -15,16 +16,24 @@ <string name="sign_in_kakao_login_fail">카카오톡 로그인에 실패했습니다</string> <string name="sign_in_kakao_cancel">로그인을 취소하였습니다</string> - <!-- Profile--> + <!--sign_up--> + <string name="sign_up_bottom_sheet_title">프로필 이미지 선택</string> + <string name="sign_up_bottom_sheet_description">회원가입 바텀시트</string> + <string name="sign_up_dialog_start">저장하기</string> + + <!--Profile--> <string name="profile_text_field_hint">이름을 입력해주세요</string> <string name="profile_text_field_helper">12자리 이내, 문자/숫자 가능, 특수문자/기호 입력불가</string> <string name="profile_text_field_warning">이름에 특수문자는 입력할 수 없어요</string> <string name="profile_text_field_check">이용 가능한 이름이에요</string> - <!-- Search--> + <!--Search--> <string name="search_text_field_hint">관심있는 인턴 공고 키워드를 검색해보세요</string> + <string name="search_today_popular">요즘 대학생들에게 인기 있는 공고</string> + <string name="search_most_view_intern">지금 조회수가 많은 공고들이에요</string> + <string name="search_most_scrap_intern">지금 스크랩 수가 많은 공고들이에요</string> - + <!--calendar--> <string name="calendar_text_sunday">일</string> <string name="calendar_text_monday">월</string> <string name="calendar_text_tuesday">화</string> @@ -35,5 +44,6 @@ <string name="calendar_button_description_previous">previous</string> <string name="calendar_button_description_next">next</string> <string name="calendar_button_description_list">list</string> + <string name="calendar_animation_label">Calendar Transition</string> </resources> \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index dfe3113c2..86c865a76 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -26,6 +26,8 @@ androidxComposeBom = "2024.04.01" androidxComposeCompiler = "1.5.14" androidxComposeMaterial3 = "1.2.1" composeNavigation = "2.8.0-beta04" +composeSavable = "1.4.3" +composeFlowRow = "0.30.0" ## Hilt hilt = "2.48.1" @@ -100,6 +102,7 @@ androidx-compose-ui-test = { group = "androidx.compose.ui", name = "ui-test-juni androidx-compose-ui-testManifest = { group = "androidx.compose.ui", name = "ui-test-manifest" } androidx-compose-navigation = { group = "androidx.navigation", name = "navigation-compose", version.ref = "composeNavigation" } androidx-compose-navigation-test = { group = "androidx.navigation", name = "navigation-testing", version.ref = "composeNavigation" } +androidx-compose-saveable = {group = "androidx.compose.runtime", name = "runtime-saveable", version.ref = "composeSavable"} compose-compiler-gradle-plugin = { module = "org.jetbrains.kotlin:compose-compiler-gradle-plugin", version.ref = "kotlin" } androidx-ui = { group = "androidx.compose.ui", name = "ui" }