diff --git a/core/build.gradle.kts b/core/build.gradle.kts index c53a6a378..01463c713 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -60,6 +60,10 @@ dependencies { // Compose Preview debugImplementation(libs.compose.ui.tooling) + //Compose Preview + implementation(libs.androidx.compose.ui.tooling) + implementation(libs.androidx.compose.ui.tooling.preview) + // Test Dependency testImplementation(libs.junit) androidTestImplementation(libs.androidx.junit) diff --git a/core/src/main/java/com/terning/core/designsystem/component/topappbar/BackButtonTopAppBar.kt b/core/src/main/java/com/terning/core/designsystem/component/topappbar/BackButtonTopAppBar.kt index 28f6b9064..dec2124c9 100644 --- a/core/src/main/java/com/terning/core/designsystem/component/topappbar/BackButtonTopAppBar.kt +++ b/core/src/main/java/com/terning/core/designsystem/component/topappbar/BackButtonTopAppBar.kt @@ -6,7 +6,7 @@ import androidx.compose.runtime.Composable fun BackButtonTopAppBar( title: String, onBackButtonClick: (() -> Unit), ) { - TerningTopAppBar( + TerningBasicTopAppBar( title = title, showBackButton = true, onBackButtonClick = { onBackButtonClick.invoke() }, diff --git a/core/src/main/java/com/terning/core/designsystem/component/topappbar/LogoTopAppBar.kt b/core/src/main/java/com/terning/core/designsystem/component/topappbar/LogoTopAppBar.kt index fcc5c62c3..f664c68c4 100644 --- a/core/src/main/java/com/terning/core/designsystem/component/topappbar/LogoTopAppBar.kt +++ b/core/src/main/java/com/terning/core/designsystem/component/topappbar/LogoTopAppBar.kt @@ -8,7 +8,7 @@ import com.terning.core.R @Composable fun LogoTopAppBar() { - TerningTopAppBar( + TerningBasicTopAppBar( showBackButton = false, actions = listOf { Icon( diff --git a/core/src/main/java/com/terning/core/designsystem/component/topappbar/MyPageTopAppBar.kt b/core/src/main/java/com/terning/core/designsystem/component/topappbar/MyPageTopAppBar.kt index 7366dc1ee..37e28fbc8 100644 --- a/core/src/main/java/com/terning/core/designsystem/component/topappbar/MyPageTopAppBar.kt +++ b/core/src/main/java/com/terning/core/designsystem/component/topappbar/MyPageTopAppBar.kt @@ -10,11 +10,11 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import com.terning.core.R -import com.terning.core.designsystem.theme.TerningTypography +import com.terning.core.designsystem.theme.TerningTheme @Composable fun MyPageTopAppBar() { - TerningTopAppBar( + TerningBasicTopAppBar( showBackButton = false, actions = listOf( {}, @@ -24,7 +24,7 @@ fun MyPageTopAppBar() { ) { Text( text = stringResource(id = R.string.my_page_top_app_bar), - style = TerningTypography().button3, + style = TerningTheme.typography.button3, textAlign = TextAlign.Center ) IconButton(onClick = { diff --git a/core/src/main/java/com/terning/core/designsystem/component/topappbar/TerningTopAppBar.kt b/core/src/main/java/com/terning/core/designsystem/component/topappbar/TerningBasicTopAppBar.kt similarity index 91% rename from core/src/main/java/com/terning/core/designsystem/component/topappbar/TerningTopAppBar.kt rename to core/src/main/java/com/terning/core/designsystem/component/topappbar/TerningBasicTopAppBar.kt index 6a319cade..1f54bb766 100644 --- a/core/src/main/java/com/terning/core/designsystem/component/topappbar/TerningTopAppBar.kt +++ b/core/src/main/java/com/terning/core/designsystem/component/topappbar/TerningBasicTopAppBar.kt @@ -10,11 +10,11 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import com.terning.core.R -import com.terning.core.designsystem.theme.TerningTypography +import com.terning.core.designsystem.theme.TerningTheme @OptIn(ExperimentalMaterial3Api::class) @Composable -fun TerningTopAppBar( +fun TerningBasicTopAppBar( title: String = "", showBackButton: Boolean = false, actions: List<@Composable () -> Unit> = emptyList(), @@ -26,7 +26,7 @@ fun TerningTopAppBar( Text( text = title, textAlign = TextAlign.Center, - style = TerningTypography().title2 + style = TerningTheme.typography.title2 ) }, @@ -50,4 +50,4 @@ fun TerningTopAppBar( } }, ) -} +} \ No newline at end of file diff --git a/core/src/main/java/com/terning/core/designsystem/textfield/NameTextField.kt b/core/src/main/java/com/terning/core/designsystem/textfield/NameTextField.kt new file mode 100644 index 000000000..6b5a9ec9a --- /dev/null +++ b/core/src/main/java/com/terning/core/designsystem/textfield/NameTextField.kt @@ -0,0 +1,37 @@ +package com.terning.core.designsystem.textfield + +import androidx.compose.runtime.Composable +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.SolidColor +import com.terning.core.designsystem.theme.Black +import com.terning.core.designsystem.theme.Grey300 +import com.terning.core.designsystem.theme.Grey400 +import com.terning.core.designsystem.theme.Grey500 +import com.terning.core.designsystem.theme.TerningMain +import com.terning.core.designsystem.theme.TerningTheme + +@Composable +fun NameTextField( + text: String, + onValueChange: (String) -> Unit, + hint: String, + helperMessage: String, + helperIcon: Int? = null, + helperColor: Color = TerningMain, +) { + TerningBasicTextField( + value = text, + onValueChange = onValueChange, + textStyle = TerningTheme.typography.detail1, + textColor = Black, + drawLineColor = Grey500, + cursorBrush = SolidColor(Grey400), + hint = hint, + hintColor = Grey300, + showTextLength = true, + maxTextLength = 12, + helperMessage = helperMessage, + helperIcon = helperIcon, + helperColor = helperColor, + ) +} \ No newline at end of file diff --git a/core/src/main/java/com/terning/core/designsystem/textfield/SearchTextField.kt b/core/src/main/java/com/terning/core/designsystem/textfield/SearchTextField.kt new file mode 100644 index 000000000..e06cfa14f --- /dev/null +++ b/core/src/main/java/com/terning/core/designsystem/textfield/SearchTextField.kt @@ -0,0 +1,29 @@ +package com.terning.core.designsystem.textfield + +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.TerningTheme + +@Composable +fun SearchTextField( + text: String, + onValueChange: (String) -> Unit, + hint: String, + leftIcon: Int, +) { +// TerningBasicTextField( +// value = text, +// onValueChange = onValueChange, +// textStyle = TerningTheme.typography.button3, +// textColor = Grey400, +// cursorBrush = SolidColor(Grey300), +// drawLineColor = Grey300, +// strokeWidth = 2f, +// hint = hint, +// hintColor = Grey300, +// leftIcon = leftIcon, +// leftIconColor = Grey400, +// ) +} \ No newline at end of file diff --git a/core/src/main/java/com/terning/core/designsystem/textfield/TerningBasicTextField.kt b/core/src/main/java/com/terning/core/designsystem/textfield/TerningBasicTextField.kt new file mode 100644 index 000000000..d100f999f --- /dev/null +++ b/core/src/main/java/com/terning/core/designsystem/textfield/TerningBasicTextField.kt @@ -0,0 +1,134 @@ +package com.terning.core.designsystem.textfield + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.text.BasicTextField +import androidx.compose.foundation.text.KeyboardActions +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material3.Icon +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.drawWithContent +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.graphics.Brush +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalFocusManager +import androidx.compose.ui.platform.LocalSoftwareKeyboardController +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.input.ImeAction +import androidx.compose.ui.unit.dp +import com.terning.core.designsystem.theme.Grey300 +import com.terning.core.designsystem.theme.TerningMain +import com.terning.core.designsystem.theme.TerningTheme +import com.terning.core.designsystem.theme.White + +@Composable +fun TerningBasicTextField( + value: String, + onValueChange: (String) -> Unit, + textStyle: TextStyle, + textColor: Color, + hintColor: Color, + drawLineColor: Color, + helperColor: Color, + cursorBrush: Brush, + strokeWidth: Float = 1f, + leftIcon: Int? = null, + leftIconColor: Color = TerningMain, + maxTextLength: Int? = null, + showTextLength: Boolean = false, + hint: String = "", + helperMessage: String = "", + helperIcon: Int? = null, +) { + val keyboardController = LocalSoftwareKeyboardController.current + val focusManager = LocalFocusManager.current + + BasicTextField(value = value, + onValueChange = onValueChange, + singleLine = true, + maxLines = 1, + keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done), + keyboardActions = KeyboardActions(onDone = { + keyboardController?.hide() + focusManager.clearFocus() + }), + + modifier = Modifier + .fillMaxWidth() + .background(White) + .drawWithContent { + val canvasWidth = size.width + val canvasHeight = size.height + + drawContent() + drawLine( + color = drawLineColor, + start = Offset(x = 0f, y = canvasHeight), + end = Offset(x = canvasWidth, y = canvasHeight), + strokeWidth = strokeWidth.dp.toPx(), + ) + }, + + textStyle = textStyle.copy(color = textColor), + cursorBrush = cursorBrush, + + decorationBox = { innerTextField -> + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(12.dp), + modifier = Modifier.padding(vertical = 8.dp) + ) { + leftIcon?.let { + Icon( + painter = painterResource(id = it), + contentDescription = null, + tint = leftIconColor, + ) + } + Box(modifier = Modifier.weight(1f)) { + if (value.isEmpty()) { + Text( + text = hint, + style = textStyle, + color = hintColor + ) + } + innerTextField() + } + if (showTextLength && maxTextLength != null) { + Text( + text = "${value.length}/$maxTextLength", + style = TerningTheme.typography.button3, + color = Grey300, + ) + } + } + }) + + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(4.dp), + modifier = Modifier.padding(vertical = 8.dp) + ) { + helperIcon?.let { + Icon( + painter = painterResource(id = it), + contentDescription = null, + tint = helperColor, + ) + } + Text( + text = helperMessage, + style = TerningTheme.typography.detail3, + color = helperColor, + ) + } +} \ No newline at end of file diff --git a/core/src/main/java/com/terning/core/extension/LocalDateExt.kt b/core/src/main/java/com/terning/core/extension/LocalDateExt.kt new file mode 100644 index 000000000..edcf61c96 --- /dev/null +++ b/core/src/main/java/com/terning/core/extension/LocalDateExt.kt @@ -0,0 +1,6 @@ +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 diff --git a/feature/build.gradle.kts b/feature/build.gradle.kts index 16da9b5ee..20541288a 100644 --- a/feature/build.gradle.kts +++ b/feature/build.gradle.kts @@ -92,6 +92,9 @@ dependencies { // Compose Preview debugImplementation(libs.compose.ui.tooling) +// //Compose Preview +// implementation(libs.androidx.compose.ui.tooling) +// implementation(libs.androidx.compose.ui.tooling.preview) // KakaoDependencies implementation(libs.kakao.user) diff --git a/feature/src/main/java/com/terning/feature/calendar/CalendarDay.kt b/feature/src/main/java/com/terning/feature/calendar/CalendarDay.kt new file mode 100644 index 000000000..fe4af64e2 --- /dev/null +++ b/feature/src/main/java/com/terning/feature/calendar/CalendarDay.kt @@ -0,0 +1,104 @@ +package com.terning.feature.calendar + +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.terning.core.designsystem.theme.Black +import com.terning.core.designsystem.theme.Grey150 +import com.terning.core.designsystem.theme.Grey200 +import com.terning.core.designsystem.theme.TerningMain +import com.terning.core.designsystem.theme.TerningPointTheme +import com.terning.core.designsystem.theme.TerningTheme +import com.terning.core.designsystem.theme.White +import com.terning.feature.calendar.models.DayModel +import java.time.LocalDate + +@Composable +fun CalendarDay( + modifier: Modifier = Modifier, + dayData: DayModel, + isSelected: Boolean, + isToday: Boolean, + onDateSelected: (LocalDate) -> Unit +) { + val backgroundColor = + if (isSelected) TerningMain else if (isToday) Grey200 else Color.Transparent + val textColor = + if (dayData.isOutDate) { + Grey150 + } else { + if (isSelected) + White + else + Black + } + + Box( + modifier = modifier, + contentAlignment = Alignment.Center + ) { + Box( + modifier = Modifier + .size(22.dp) + .clickable( + interactionSource = remember { MutableInteractionSource() }, + indication = null, + onClick = { + if (!dayData.isOutDate) { + onDateSelected(dayData.date) + } + } + ) + .background( + color = backgroundColor, + shape = CircleShape + ), + contentAlignment = Alignment.Center + ) { + Text( + text = dayData.date.dayOfMonth.toString(), + color = textColor, + style = TerningTheme.typography.calendar + ) + } + } +} + +@Preview(showBackground = true) +@Composable +fun CalendarDayPreview() { + TerningPointTheme { + Row { + CalendarDay( + dayData = DayModel(LocalDate.now(), false), + isSelected = true, + isToday = true, + onDateSelected = {} + ) + CalendarDay( + dayData = DayModel(LocalDate.now(), false), + isSelected = false, + isToday = true, + onDateSelected = {} + ) + CalendarDay( + dayData = DayModel(LocalDate.now(), false), + isSelected = false, + isToday = false, + onDateSelected = {} + ) + } + } +} \ No newline at end of file diff --git a/feature/src/main/java/com/terning/feature/calendar/CalendarMonth.kt b/feature/src/main/java/com/terning/feature/calendar/CalendarMonth.kt new file mode 100644 index 000000000..ef34392fa --- /dev/null +++ b/feature/src/main/java/com/terning/feature/calendar/CalendarMonth.kt @@ -0,0 +1,87 @@ +package com.terning.feature.calendar + +import androidx.compose.foundation.background +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 +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +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.feature.calendar.models.MonthData +import com.terning.feature.calendar.models.Scrap +import java.time.LocalDate +import java.time.YearMonth + +@Composable +fun CalendarMonth( + modifier: Modifier = Modifier, + monthData: MonthData, + onDateSelected: (LocalDate) -> Unit, + selectedDate: LocalDate, + scrapLists: List> = listOf() +) { + Column( + modifier = modifier + .fillMaxSize() + .padding(horizontal = 20.dp), + ) { + val month = monthData.calendarMonth.weekDays + for (week in month) { + Row( + modifier = Modifier.weight(1f), + ) { + for (day in week) { + Column( + modifier = Modifier + .weight(1f) + .padding(top = 15.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + CalendarDay( + dayData = day, + isSelected = selectedDate == day.date, + isToday = day.date == LocalDate.now(), + onDateSelected = onDateSelected + ) + if(!day.isOutDate) { + val index = day.date.dayOfWeek.value - 1 + CalendarScrap( + scrapList = scrapLists[index] + ) + } + } + } + } + if(month.indexOf(week) != month.lastIndex) { + Spacer( + modifier = Modifier + .fillMaxWidth() + .height(1.dp) + .background(color = Grey150) + ) + } + } + } +} + +@Preview(showBackground = true) +@Composable +fun CalendarMonthPreview() { + TerningPointTheme { + CalendarMonth( + monthData = MonthData(YearMonth.now()), + selectedDate = LocalDate.now(), + onDateSelected = {}, + scrapLists = listOf() + ) + } +} \ No newline at end of file diff --git a/feature/src/main/java/com/terning/feature/calendar/CalendarMonths.kt b/feature/src/main/java/com/terning/feature/calendar/CalendarMonths.kt new file mode 100644 index 000000000..4f179af8d --- /dev/null +++ b/feature/src/main/java/com/terning/feature/calendar/CalendarMonths.kt @@ -0,0 +1,48 @@ +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 +import androidx.compose.ui.Modifier +import com.terning.core.designsystem.theme.White +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 java.time.LocalDate +import java.time.YearMonth + +@Composable +fun CalendarMonths( + modifier: Modifier = Modifier, + listState: LazyListState, + onDateSelected: (LocalDate) -> Unit, + pages: Int, + selectedDate: LocalDate, + scrapLists: List> +) { + LazyRow( + modifier = modifier + .background(White), + state = listState, + userScrollEnabled = true, + flingBehavior = flingBehavior( + state = listState + ) + ) { + items(pages) { page -> + val date = getDateByPage(page) + val monthData = MonthData(YearMonth.of(date.year, date.month)) + + CalendarMonth( + modifier = Modifier.fillParentMaxSize(), + selectedDate = selectedDate, + onDateSelected = onDateSelected, + monthData = monthData, + scrapLists = scrapLists + ) + } + } +} \ No newline at end of file diff --git a/feature/src/main/java/com/terning/feature/calendar/CalendarRoute.kt b/feature/src/main/java/com/terning/feature/calendar/CalendarRoute.kt new file mode 100644 index 000000000..c706c5715 --- /dev/null +++ b/feature/src/main/java/com/terning/feature/calendar/CalendarRoute.kt @@ -0,0 +1,116 @@ +package com.terning.feature.calendar + +import androidx.activity.compose.BackHandler +import androidx.compose.foundation.background +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.lazy.rememberLazyListState +import androidx.compose.material3.Scaffold +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.setValue +import androidx.compose.runtime.snapshotFlow +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import androidx.hilt.navigation.compose.hiltViewModel +import com.terning.core.designsystem.theme.Grey200 +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 + +@Composable +fun CalendarRoute() { + CalendarScreen() +} + +@Composable +fun CalendarScreen( + modifier: Modifier = Modifier, + viewModel: CalendarViewModel = hiltViewModel() +) { + val selectedDate by viewModel.selectedDate.collectAsState() + 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 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() + currentDate = currentDate.plusMonths(swipeDirection) + currentPage = listState.firstVisibleItemIndex + } + } + + LaunchedEffect(key1 = selectedDate) { + isWeekEnabled = true + } + + BackHandler { + isWeekEnabled = false + } + + Scaffold( + modifier = modifier, + topBar = { + val coroutineScope = rememberCoroutineScope() + CalendarTopBar( + date = currentDate, + isListExpanded = isListExpanded, + onListButtonClicked = { isListExpanded = !isListExpanded }, + onMonthNavigationButtonClicked = { direction -> + coroutineScope.launch { + listState.animateScrollToItem( + index = listState.firstVisibleItemIndex + direction, + ) + } + } + ) + } + ) { paddingValues -> + Column( + modifier = Modifier + .fillMaxWidth() + .padding(top = paddingValues.calculateTopPadding()) + ) { + WeekDaysHeader() + Spacer(modifier = Modifier + .fillMaxWidth() + .height(1.dp) + .background(color = Grey200) + ) + CalendarMonths( + modifier = Modifier.fillMaxSize(), + selectedDate = selectedDate, + onDateSelected = { + viewModel.updateSelectedDate(it) + }, + listState = listState, + pages = state.getPageCount(), + scrapLists = viewModel.mockScrapList + ) + } + + } +} diff --git a/feature/src/main/java/com/terning/feature/calendar/CalendarRouth.kt b/feature/src/main/java/com/terning/feature/calendar/CalendarRouth.kt deleted file mode 100644 index 76ef0be7f..000000000 --- a/feature/src/main/java/com/terning/feature/calendar/CalendarRouth.kt +++ /dev/null @@ -1,19 +0,0 @@ -package com.terning.feature.calendar - -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier - -@Composable -fun CalendarRoute() { - CalendarScreen() -} - -@Composable -fun CalendarScreen() { - Column(modifier = Modifier.fillMaxSize()) { - Text(text = "캘린더 스크린") - } -} \ No newline at end of file diff --git a/feature/src/main/java/com/terning/feature/calendar/CalendarScrap.kt b/feature/src/main/java/com/terning/feature/calendar/CalendarScrap.kt new file mode 100644 index 000000000..a28d47c19 --- /dev/null +++ b/feature/src/main/java/com/terning/feature/calendar/CalendarScrap.kt @@ -0,0 +1,55 @@ +package com.terning.feature.calendar + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.dp +import com.terning.core.designsystem.theme.TerningTheme +import com.terning.core.designsystem.theme.White +import com.terning.feature.calendar.models.Scrap + +@Composable +fun CalendarScrap( + modifier: Modifier = Modifier, + scrapList: List +) { + LazyColumn( + modifier = modifier.fillMaxWidth().padding(top = 3.dp) + ) { + items(scrapList.subList(0, MAX_SCRAP_COUNT.coerceAtMost(scrapList.size))) { scrap -> + Text( + text = scrap.text, + style = TerningTheme.typography.body5, + textAlign = TextAlign.Center, + color = White, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + modifier = Modifier + .fillMaxWidth() + .background(color = scrap.backgroundColor) + ) + } + + item{ + if(scrapList.size > MAX_SCRAP_COUNT) { + Text( + text = "+${(scrapList.size - MAX_SCRAP_COUNT)}", + style = TerningTheme.typography.detail4, + textAlign = TextAlign.Center, + modifier = Modifier.fillMaxWidth() + ) + } + } + + } +} + +private const val MAX_SCRAP_COUNT = 2 + diff --git a/feature/src/main/java/com/terning/feature/calendar/CalendarViewModel.kt b/feature/src/main/java/com/terning/feature/calendar/CalendarViewModel.kt new file mode 100644 index 000000000..d57863782 --- /dev/null +++ b/feature/src/main/java/com/terning/feature/calendar/CalendarViewModel.kt @@ -0,0 +1,93 @@ +package com.terning.feature.calendar + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.terning.core.designsystem.theme.CalBlue1 +import com.terning.core.designsystem.theme.CalGreen1 +import com.terning.core.designsystem.theme.CalGreen2 +import com.terning.core.designsystem.theme.CalPink +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 dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch +import java.time.LocalDate +import javax.inject.Inject + +@HiltViewModel +class CalendarViewModel @Inject constructor( +) : ViewModel() { + private val _selectedDate = MutableStateFlow(LocalDate.now()) + val selectedDate get() = _selectedDate.asStateFlow() + + fun updateSelectedDate(date: LocalDate) = viewModelScope.launch { + if (_selectedDate.value != date) { + _selectedDate.value = date + } + } + + //To be erased in future + val mockScrapList: List> + get() { + val list: MutableList> = mutableListOf() + for (i in 0..30) { + when (i % 6) { + 0 -> { + list.add( + i, + listOf() + ) + } + + 1 -> { + list.add( + i, + listOf( + Scrap("Task1_1", CalBlue1), + ) + ) + } + + 2 -> { + list.add( + i, + listOf( + Scrap("Task2_1", CalPink), + Scrap("Task2_2", CalGreen1) + ) + ) + } + 3 -> { + list.add( + i, + listOf() + ) + } + 4 -> { + list.add( + i, + listOf() + ) + } + 5 -> { + list.add( + i, + listOf( + Scrap("Task3_1", CalPink), + Scrap("Task3_2", CalPurple), + Scrap("Task3_3", CalRed), + Scrap("Task3_4", CalBlue1), + Scrap("Task3_5", CalGreen2), + Scrap("Task3_6", CalYellow) + ) + ) + } + } + } + return list.toList() + } +} \ No newline at end of file diff --git a/feature/src/main/java/com/terning/feature/calendar/component/CalendarTopBar.kt b/feature/src/main/java/com/terning/feature/calendar/component/CalendarTopBar.kt new file mode 100644 index 000000000..bdfcf8ffd --- /dev/null +++ b/feature/src/main/java/com/terning/feature/calendar/component/CalendarTopBar.kt @@ -0,0 +1,100 @@ +package com.terning.feature.calendar.component + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Icon +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.terning.core.designsystem.theme.Black +import com.terning.core.designsystem.theme.Grey300 +import com.terning.core.designsystem.theme.TerningPointTheme +import com.terning.core.designsystem.theme.TerningTheme +import com.terning.core.extension.getStringAsTitle +import com.terning.core.extension.noRippleClickable +import com.terning.feature.R +import java.time.LocalDate + +@Composable +fun CalendarTopBar( + modifier: Modifier = Modifier, + date: LocalDate, + isListExpanded: Boolean, + onListButtonClicked: () -> Unit, + onMonthNavigationButtonClicked: (Int) -> Unit, +) { + Box( + modifier = modifier + .fillMaxWidth() + .background(color = Color.White) + .padding( + top = 23.dp, + bottom = 22.dp, + start = 22.dp, + end = 22.dp + ) + ) { + Row( + modifier = Modifier.align(Alignment.Center), + verticalAlignment = Alignment.CenterVertically + ) { + Icon( + painter = painterResource(id = R.drawable.ic_calendar_previous), + contentDescription = stringResource(id = R.string.calendar_button_description_previous), + tint = Grey300, + modifier = Modifier.noRippleClickable { onMonthNavigationButtonClicked(-1) } + ) + Text( + text = date.getStringAsTitle(), + style = TerningTheme.typography.title2, + color = Black, + modifier = Modifier.padding(horizontal = 8.dp) + ) + Icon( + painter = painterResource(id = R.drawable.ic_calendar_next), + contentDescription = stringResource(id = R.string.calendar_button_description_next), + tint = Grey300, + modifier = Modifier.noRippleClickable { onMonthNavigationButtonClicked(1) } + ) + } + Box( + modifier = Modifier + .align(Alignment.CenterEnd) + ) { + Icon( + painter = painterResource( + id = if (isListExpanded) { + R.drawable.ic_calendar_list_selected + } else { + R.drawable.ic_calendar_list_unselected + } + ), + contentDescription = stringResource(id = R.string.calendar_button_description_list), + modifier = Modifier.noRippleClickable { onListButtonClicked() }, + tint = if (isListExpanded) Color.Green else Color.LightGray, + ) + } + } +} + +@Preview(showBackground = true) +@Composable +fun CalendarTopBarPreview() { + TerningPointTheme { + CalendarTopBar( + date = LocalDate.now(), + isListExpanded = false, + onListButtonClicked = {}, + onMonthNavigationButtonClicked = {} + ) + } +} \ No newline at end of file diff --git a/feature/src/main/java/com/terning/feature/calendar/component/WeekDaysHeader.kt b/feature/src/main/java/com/terning/feature/calendar/component/WeekDaysHeader.kt new file mode 100644 index 000000000..d4983af70 --- /dev/null +++ b/feature/src/main/java/com/terning/feature/calendar/component/WeekDaysHeader.kt @@ -0,0 +1,58 @@ +package com.terning.feature.calendar.component + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.terning.core.designsystem.theme.Black +import com.terning.core.designsystem.theme.SundayRed +import com.terning.core.designsystem.theme.TerningTheme +import com.terning.feature.R + +@Composable +fun WeekDaysHeader( + modifier: Modifier = Modifier, +) { + Row( + modifier = modifier + .fillMaxWidth() + .background(Color.White) + .padding( + horizontal = 20.dp, + vertical = 18.dp), + ){ + val dayOfWeek = listOf( + R.string.calendar_text_sunday, + R.string.calendar_text_monday, + R.string.calendar_text_tuesday, + R.string.calendar_text_wednesday, + R.string.calendar_text_thursday, + R.string.calendar_text_friday, + R.string.calendar_text_saturday,) + dayOfWeek.forEach { day -> + Text( + modifier = Modifier.weight(1f), + text = stringResource(id = day), + style = TerningTheme.typography.body7, + color = if(day == R.string.calendar_text_sunday) SundayRed else Black, + textAlign = TextAlign.Center + ) + } + } +} + +@Preview(showBackground = true) +@Composable +fun WeekDaysHeaderPreview() { + TerningTheme{ + WeekDaysHeader() + } +} \ No newline at end of file diff --git a/feature/src/main/java/com/terning/feature/calendar/models/CalendarDefault.kt b/feature/src/main/java/com/terning/feature/calendar/models/CalendarDefault.kt new file mode 100644 index 000000000..59a554d7d --- /dev/null +++ b/feature/src/main/java/com/terning/feature/calendar/models/CalendarDefault.kt @@ -0,0 +1,34 @@ +package com.terning.feature.calendar.models + +import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.foundation.gestures.FlingBehavior +import androidx.compose.foundation.gestures.snapping.SnapLayoutInfoProvider +import androidx.compose.foundation.gestures.snapping.SnapPosition +import androidx.compose.foundation.gestures.snapping.rememberSnapFlingBehavior +import androidx.compose.foundation.lazy.LazyListState +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember + +internal object CalendarDefaults { + /** + * Returns the fling behavior for the given [LazyListState]. + * From Github [https://github.com/kizitonwose/Calendar] + */ + @OptIn(ExperimentalFoundationApi::class) + @Composable + fun flingBehavior(state: LazyListState): FlingBehavior { + val snappingLayout = remember(state) { + val provider = SnapLayoutInfoProvider(state, SnapPosition.Start) + CalendarSnapLayoutInfoProvider(provider) + } + return rememberSnapFlingBehavior(snappingLayout) + } +} + +@ExperimentalFoundationApi +@Suppress("FunctionName") +private fun CalendarSnapLayoutInfoProvider( + snapLayoutInfoProvider: SnapLayoutInfoProvider, +): SnapLayoutInfoProvider = object : SnapLayoutInfoProvider by snapLayoutInfoProvider { + override fun calculateApproachOffset(velocity: Float, decayOffset: Float): Float = 0f +} \ No newline at end of file diff --git a/feature/src/main/java/com/terning/feature/calendar/models/CalendarState.kt b/feature/src/main/java/com/terning/feature/calendar/models/CalendarState.kt new file mode 100644 index 000000000..98e3cfd94 --- /dev/null +++ b/feature/src/main/java/com/terning/feature/calendar/models/CalendarState.kt @@ -0,0 +1,58 @@ +package com.terning.feature.calendar.models + +import androidx.compose.runtime.Stable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue +import java.time.LocalDate +import java.time.YearMonth + +@Stable +class CalendarState internal constructor( + startMonth: YearMonth = YearMonth.of(START_YEAR, 1), + endMonth: YearMonth = YearMonth.of(END_YEAR, 12), + firstVisibleMonth: YearMonth = YearMonth.now(), +) { + private var _startMonth by mutableStateOf(startMonth) + var startMonth: YearMonth + get() = _startMonth + set(value) { + if (value != _startMonth) { + _startMonth = value + } + } + + private var _endMonth by mutableStateOf(endMonth) + var endMonth: YearMonth + get() = _endMonth + set(value) { + if (value != _endMonth) { + _endMonth = value + } + } + + private var _firstVisibleMonth by mutableStateOf(firstVisibleMonth) + var firstVisibleMonth: YearMonth + get() = _firstVisibleMonth + set(value) { + if (value != _firstVisibleMonth) { + _firstVisibleMonth = value + } + } + + fun getPageCount(): Int = (END_YEAR - START_YEAR) * 12 + + fun getInitialPage(): Int = + (firstVisibleMonth.year - START_YEAR) * 12 + firstVisibleMonth.monthValue - 1 + + companion object { + const val START_YEAR = 2020 + const val END_YEAR = 2030 + + fun getDateByPage(page: Int): LocalDate = LocalDate.of( + START_YEAR + page / 12, + page % 12 + 1, + 1 + ) + } +} \ No newline at end of file diff --git a/feature/src/main/java/com/terning/feature/calendar/models/DayModel.kt b/feature/src/main/java/com/terning/feature/calendar/models/DayModel.kt new file mode 100644 index 000000000..891a9f470 --- /dev/null +++ b/feature/src/main/java/com/terning/feature/calendar/models/DayModel.kt @@ -0,0 +1,10 @@ +package com.terning.feature.calendar.models + +import androidx.compose.runtime.Immutable +import java.time.LocalDate + +@Immutable +data class DayModel( + val date: LocalDate, + val isOutDate: Boolean = false +) \ No newline at end of file diff --git a/feature/src/main/java/com/terning/feature/calendar/models/MonthData.kt b/feature/src/main/java/com/terning/feature/calendar/models/MonthData.kt new file mode 100644 index 000000000..425f7beb6 --- /dev/null +++ b/feature/src/main/java/com/terning/feature/calendar/models/MonthData.kt @@ -0,0 +1,41 @@ +package com.terning.feature.calendar.models + +import androidx.compose.runtime.Immutable +import java.time.YearMonth + +/** + * [MonthData] is responsible for managing a month's overall characteristics + * it consists of following properties:- + * + * [inDays] represents the number of days in the previous month that should be shown before the first day of the month. + * [outDays] represents the number of days in the next month that should be shown after the last day of the month.] + * [totalDays] represents the total number of days shown on calendar + * [calendarMonth] represents the list of days of the month, a list of [DayModel] + */ + + +@Immutable +data class MonthData( + val month: YearMonth +) { + private val firstDayOfWeek = month.atDay(1).dayOfWeek.value + private val previousMonth = month.minusMonths(1) + private val nextMonth = month.plusMonths(1) + + val inDays = firstDayOfWeek % 7 + val monthDays = month.lengthOfMonth() + val outDays = (7 - ((inDays + monthDays) % 7)) % 7 + val totalDays = monthDays + inDays + outDays + + private val rows = (0 until totalDays).chunked(7) + + val calendarMonth = MonthModel(month, rows.map { week -> week.map {dayOffset -> getDay(dayOffset)}}) + + private fun getDay(dayOffset: Int): DayModel { + val firstDayOnCalendar = month.atDay(1).minusDays(inDays.toLong()) + val date = firstDayOnCalendar.plusDays(dayOffset.toLong()) + val isOutDate = YearMonth.of(date.year, date.monthValue) != month + + return DayModel(date, isOutDate) + } +} diff --git a/feature/src/main/java/com/terning/feature/calendar/models/MonthModel.kt b/feature/src/main/java/com/terning/feature/calendar/models/MonthModel.kt new file mode 100644 index 000000000..01a10041d --- /dev/null +++ b/feature/src/main/java/com/terning/feature/calendar/models/MonthModel.kt @@ -0,0 +1,37 @@ +package com.terning.feature.calendar.models + +import androidx.compose.runtime.Immutable +import java.time.YearMonth + +@Immutable +data class MonthModel( + val yearMonth: YearMonth, + val weekDays: List> +) { + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as MonthModel + + if (yearMonth != other.yearMonth) return false + if (weekDays.first().first() != other.weekDays.first().first()) return false + if (weekDays.last().last() != other.weekDays.last().last()) return false + + return true + } + + override fun hashCode(): Int { + var result = yearMonth.hashCode() + result = 31 * result + weekDays.first().first().hashCode() + result = 31 * result + weekDays.last().last().hashCode() + return result + } + + override fun toString(): String { + return "CalendarMonth { " + + "first = ${weekDays.first().first()}, " + + "last = ${weekDays.last().last()} " + + "} " + } +} diff --git a/feature/src/main/java/com/terning/feature/calendar/models/Scrap.kt b/feature/src/main/java/com/terning/feature/calendar/models/Scrap.kt new file mode 100644 index 000000000..73698591a --- /dev/null +++ b/feature/src/main/java/com/terning/feature/calendar/models/Scrap.kt @@ -0,0 +1,10 @@ +package com.terning.feature.calendar.models + +import androidx.compose.runtime.Immutable +import androidx.compose.ui.graphics.Color + +@Immutable +data class Scrap( + val text: String, + val backgroundColor: Color +) 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/main/MainScreen.kt b/feature/src/main/java/com/terning/feature/main/MainScreen.kt index 098091c61..863c5235b 100644 --- a/feature/src/main/java/com/terning/feature/main/MainScreen.kt +++ b/feature/src/main/java/com/terning/feature/main/MainScreen.kt @@ -16,13 +16,12 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.navigation.compose.NavHost -import com.terning.core.designsystem.component.topappbar.BackButtonTopAppBar import com.terning.core.designsystem.component.topappbar.LogoTopAppBar import com.terning.core.designsystem.component.topappbar.MyPageTopAppBar -import com.terning.core.designsystem.component.topappbar.TerningTopAppBar import com.terning.core.designsystem.theme.Grey300 import com.terning.core.designsystem.theme.TerningMain import com.terning.core.designsystem.theme.White +import com.terning.core.designsystem.component.topappbar.TerningBasicTopAppBar import com.terning.core.util.NoRippleInteractionSource import com.terning.feature.calendar.navigation.calendarNavGraph import com.terning.feature.home.navigation.homeNavGraph @@ -39,13 +38,10 @@ fun MainScreen( topBar = { when (navigator.currentTab) { MainTab.HOME -> LogoTopAppBar() - MainTab.CALENDAR -> BackButtonTopAppBar( - title = "dkssud", - onBackButtonClick = { navigator.navigateUp() }) - + MainTab.CALENDAR -> TerningBasicTopAppBar() MainTab.SEARCH -> LogoTopAppBar() MainTab.MY_PAGE -> MyPageTopAppBar() - null -> TerningTopAppBar() + null -> TerningBasicTopAppBar() } }, bottomBar = { @@ -77,6 +73,20 @@ fun MainScreen( } } + +@Composable +private fun MainTopBar( + isVisible: Boolean, + tabs: List, + currentTab: MainTab?, + onTabSelected: (MainTab) -> Unit, +) { + AnimatedVisibility( + visible = isVisible, + ) { + } +} + @Composable private fun MainBottomBar( isVisible: Boolean, 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 1e374e3b7..1c2531d5a 100644 --- a/feature/src/main/java/com/terning/feature/search/SearchRoute.kt +++ b/feature/src/main/java/com/terning/feature/search/SearchRoute.kt @@ -1,10 +1,26 @@ package com.terning.feature.search +import androidx.compose.foundation.gestures.detectTapGestures import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier +import androidx.compose.ui.input.pointer.pointerInput +import androidx.compose.ui.platform.LocalFocusManager +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import com.terning.core.designsystem.textfield.NameTextField +import com.terning.core.designsystem.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.feature.R @Composable fun SearchRoute() { @@ -12,11 +28,63 @@ fun SearchRoute() { } @Composable -fun SearchScreen(modifier: Modifier = Modifier) { +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(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 + } + } + Column( modifier = Modifier .fillMaxWidth() + .padding(horizontal = 16.dp) ) { - Text(text = "탐색 스크린") + + SearchTextField( + text = text, + onValueChange = { newText -> + text = newText + }, + hint = stringResource(R.string.search_text_field_hint), + leftIcon = R.drawable.ic_nav_search + ) + + // 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 + ) } } diff --git a/feature/src/main/res/drawable/ic_calendar_list_selected.xml b/feature/src/main/res/drawable/ic_calendar_list_selected.xml new file mode 100644 index 000000000..686920353 --- /dev/null +++ b/feature/src/main/res/drawable/ic_calendar_list_selected.xml @@ -0,0 +1,13 @@ + + + + + + diff --git a/feature/src/main/res/drawable/ic_calendar_list_unselected.xml b/feature/src/main/res/drawable/ic_calendar_list_unselected.xml new file mode 100644 index 000000000..fa8821985 --- /dev/null +++ b/feature/src/main/res/drawable/ic_calendar_list_unselected.xml @@ -0,0 +1,13 @@ + + + + + + diff --git a/feature/src/main/res/drawable/ic_calendar_next.xml b/feature/src/main/res/drawable/ic_calendar_next.xml new file mode 100644 index 000000000..36a9b4af7 --- /dev/null +++ b/feature/src/main/res/drawable/ic_calendar_next.xml @@ -0,0 +1,9 @@ + + + diff --git a/feature/src/main/res/drawable/ic_calendar_previous.xml b/feature/src/main/res/drawable/ic_calendar_previous.xml new file mode 100644 index 000000000..f9001fd4b --- /dev/null +++ b/feature/src/main/res/drawable/ic_calendar_previous.xml @@ -0,0 +1,13 @@ + + + + + + diff --git a/feature/src/main/res/drawable/ic_check.xml b/feature/src/main/res/drawable/ic_check.xml new file mode 100644 index 000000000..3982b4d78 --- /dev/null +++ b/feature/src/main/res/drawable/ic_check.xml @@ -0,0 +1,18 @@ + + + + diff --git a/feature/src/main/res/drawable/ic_nav_home.xml b/feature/src/main/res/drawable/ic_nav_home.xml index 6fcd9a120..9b5f41b94 100644 --- a/feature/src/main/res/drawable/ic_nav_home.xml +++ b/feature/src/main/res/drawable/ic_nav_home.xml @@ -3,7 +3,7 @@ android:height="18dp" android:viewportWidth="18" android:viewportHeight="18"> - - + + \ No newline at end of file diff --git a/feature/src/main/res/drawable/ic_warning.xml b/feature/src/main/res/drawable/ic_warning.xml new file mode 100644 index 000000000..04eb2ddbe --- /dev/null +++ b/feature/src/main/res/drawable/ic_warning.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/feature/src/main/res/values/strings.xml b/feature/src/main/res/values/strings.xml index 71aa3bf69..2247cdd3a 100644 --- a/feature/src/main/res/values/strings.xml +++ b/feature/src/main/res/values/strings.xml @@ -15,4 +15,25 @@ 카카오톡 로그인에 실패했습니다 로그인을 취소하였습니다 + + 이름을 입력해주세요 + 12자리 이내, 문자/숫자 가능, 특수문자/기호 입력불가 + 이름에 특수문자는 입력할 수 없어요 + 이용 가능한 이름이에요 + + + 관심있는 인턴 공고 키워드를 검색해보세요 + + + + + + + + + + previous + next + list + \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index add53ee0a..623eb7a00 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -97,8 +97,8 @@ androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", versi androidx-compose-material3 = { group = "androidx.compose.material3", name = "material3", version.ref = "androidxComposeMaterial3" } androidx-compose-ui = { group = "androidx.compose.ui", name = "ui" } androidx-compose-ui-test = { group = "androidx.compose.ui", name = "ui-test-junit4" } -androidx-compose-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" } -androidx-compose-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" } +androidx-compose-ui-tooling = { group = "androidx.compose.ui", name = "uiTooling" } +androidx-compose-ui-tooling-preview = { group = "androidx.compose.ui", name = "uiTooling" } 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" } @@ -119,7 +119,6 @@ android-desugarJdkLibs = { group = "com.android.tools", name = "desugar_jdk_libs androidx-lifecycle-runtimeCompose = { group = "androidx.lifecycle", name = "lifecycle-runtime-compose", version.ref = "androidxLifecycle" } androidx-lifecycle-viewModelCompose = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-compose", version.ref = "androidxLifecycle" } androidx-datastore = { group = "androidx.datastore", name = "datastore-preferences", version.ref = "androidxDatastore" } -compose-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling", version.ref = "uiTooling" } hilt-core = { group = "com.google.dagger", name = "hilt-core", version.ref = "hilt" } hilt-compiler = { group = "com.google.dagger", name = "hilt-compiler", version.ref = "hilt" } @@ -158,6 +157,9 @@ lottie = {group = "com.airbnb.android", name = "lottie", version.ref = "lottieVe kakao-user = {group = "com.kakao.sdk", name = "v2-user", version.ref = "kakaoVersion"} +compose-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling", version.ref = "uiTooling" } + + [plugins] android-application = { id = "com.android.application", version.ref = "androidGradlePlugin" } kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }