diff --git a/app/src/main/java/org/sopt/cgv/core/designsystem/component/card/CompTimeCard.kt b/app/src/main/java/org/sopt/cgv/core/designsystem/component/card/CompTimeCard.kt new file mode 100644 index 0000000..0327693 --- /dev/null +++ b/app/src/main/java/org/sopt/cgv/core/designsystem/component/card/CompTimeCard.kt @@ -0,0 +1,151 @@ +package org.sopt.cgv.core.designsystem.component.card + +import android.os.Build +import androidx.annotation.RequiresApi +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.RoundedCornerShape +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.clip +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import org.sopt.cgv.core.designsystem.theme.* +import org.sopt.cgv.R +import java.time.LocalDateTime +import java.time.format.DateTimeFormatter + +@RequiresApi(Build.VERSION_CODES.O) +@Composable +fun CompTimeCard( + modifier: Modifier = Modifier, + startTime: LocalDateTime, + endTime: LocalDateTime, + currentSeats: Int, + totalSeats: Int, + isMorning: Boolean, + isActivated: Boolean = false, + onClick: () -> Unit, +){ + + + val backgroundColor = if (isActivated) White else Gray700 + val backgroundColor2 = if (isActivated) Gray200 else Gray700 + val leftSeatsColor = if (isActivated) PrimaryRed400 else Green + + val timeFormatter = DateTimeFormatter.ofPattern("HH:mm") + val formattedStartTime = startTime.format(timeFormatter) + val formattedEndTime = endTime.format(timeFormatter) + + Box( + modifier = modifier + .size(width = 90.dp, height = 64.dp) + .clip(RoundedCornerShape(8.dp)) + .background(backgroundColor) + .border(width = 1.dp, color = Gray200, shape = RoundedCornerShape(8.dp)) + .clickable { + onClick() + } + ){ + Column( + modifier = modifier.fillMaxSize(), + verticalArrangement = Arrangement.SpaceBetween + ){ + //시간 부분 + Row( + modifier = modifier + .size(width = 90.dp, height = 41.dp) + .padding(horizontal = 8.dp, vertical = 10.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.Center, + ){ + Text( + text = formattedStartTime, + color = Black, + style = Typography.head1_b_16 + ) + Text( + modifier = Modifier.padding(top = 4.dp), + text = "~$formattedEndTime", + color = Gray600, + style = Typography.body0_r_8 + ) + } + //잔여 좌석 부분 + Row( + modifier = modifier + .fillMaxWidth() + .height(23.dp) + .background(backgroundColor2), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.SpaceAround, + ){ + Row( + modifier = modifier + .padding(top = 3.dp, bottom = 3.dp, start = 9.dp, end = 8.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.SpaceAround, + ){ + if(isMorning){ + Icon( + painter = painterResource(id = R.drawable.ic_time_sun), + contentDescription = "morning movie", + tint = Gray700, + modifier = modifier.size(16.dp) + ) + } + Text( + text = "$currentSeats", + color = leftSeatsColor, + style = Typography.body2_r_12 + ) + Text( + text = "/", + color = Black, + style = Typography.body2_r_12 + ) + Text( + text = "${totalSeats}석", + color = Black, + style = Typography.body2_r_12 + ) + } + } + + } + } +} + +@RequiresApi(Build.VERSION_CODES.O) +@Preview(showBackground = true) +@Composable +fun CompTimeCardPreview() { + CompTimeCard( + modifier = Modifier, + startTime = LocalDateTime.of(2024, 11, 19, 7, 50), + endTime = LocalDateTime.of(2024, 11, 19, 9, 41), + currentSeats = 183, + totalSeats = 185, + isMorning = true, + isActivated = true, + onClick = {} + ) +} + + + + diff --git a/app/src/main/java/org/sopt/cgv/core/designsystem/component/chip/Chip.kt b/app/src/main/java/org/sopt/cgv/core/designsystem/component/chip/Chip.kt new file mode 100644 index 0000000..2e5b75d --- /dev/null +++ b/app/src/main/java/org/sopt/cgv/core/designsystem/component/chip/Chip.kt @@ -0,0 +1,44 @@ +package org.sopt.cgv.core.designsystem.component.chip + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +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.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import org.sopt.cgv.core.designsystem.theme.Gray100 +import org.sopt.cgv.core.designsystem.theme.Gray700 +import org.sopt.cgv.core.designsystem.theme.Typography + +@Composable +fun Chip( + modifier: Modifier = Modifier, + content: String +){ + + Box( + modifier = Modifier + .clip(RoundedCornerShape(8.dp)) + .background(Gray100) + .padding(vertical = 6.dp, horizontal = 8.dp), + ){ + Text( + text = content, + color = Gray700, + style = Typography.head3_b_14 + ) + } +} + +@Preview +@Composable +fun SeatChoiceModalChipPreview(){ + Chip( + modifier = Modifier, + content = "2024.11.9 (토)" + ) +} \ No newline at end of file diff --git a/app/src/main/java/org/sopt/cgv/feature/seats/SeatSelectionChipRow.kt b/app/src/main/java/org/sopt/cgv/feature/seats/SeatSelectionChipRow.kt new file mode 100644 index 0000000..e200f22 --- /dev/null +++ b/app/src/main/java/org/sopt/cgv/feature/seats/SeatSelectionChipRow.kt @@ -0,0 +1,40 @@ +package org.sopt.cgv.feature.seats + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import org.sopt.cgv.core.designsystem.component.chip.Chip +import androidx.compose.ui.Alignment + +@Composable +fun SeatSelectionChipRow( + modifier: Modifier = Modifier, + contents: List, +){ + Row( + horizontalArrangement = Arrangement.spacedBy(8.dp, Alignment.CenterHorizontally), + modifier = modifier.fillMaxWidth() + ) { + contents.forEach { + chipContent -> + Chip(content = chipContent) + } + } + +} + + +@Preview(showBackground = true) +@Composable +fun SeatSelectionChipRowPreview(){ + val ChipContents = listOf( + "2024.11.05 (월)", + "구리", + "10:40 ~ 12:39" + ) + SeatSelectionChipRow(contents = ChipContents) +} \ No newline at end of file diff --git a/app/src/main/java/org/sopt/cgv/feature/seats/SeatSelectionModal1.kt b/app/src/main/java/org/sopt/cgv/feature/seats/SeatSelectionModal1.kt new file mode 100644 index 0000000..af1e1d5 --- /dev/null +++ b/app/src/main/java/org/sopt/cgv/feature/seats/SeatSelectionModal1.kt @@ -0,0 +1,123 @@ +package org.sopt.cgv.feature.seats + +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.* +import androidx.compose.runtime.* +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 org.sopt.cgv.core.designsystem.component.button.CgvButton +import org.sopt.cgv.core.designsystem.theme.Black +import org.sopt.cgv.core.designsystem.theme.CGVTheme +import org.sopt.cgv.core.designsystem.theme.PrimaryRed400 +import org.sopt.cgv.core.designsystem.theme.Typography + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun SeatSelectionModal1( + modifier: Modifier = Modifier, + seatSelectionMovieTitle: String, + chipContents: List, + onBackClick: () -> Unit, + onSeatSelectionClick: () -> Unit +) { + ModalBottomSheet( + onDismissRequest = { }, + sheetState = rememberModalBottomSheetState( + skipPartiallyExpanded = true + ), + shape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp), + containerColor = Color.White + ) { + Column( + modifier = Modifier + .padding(16.dp) + .fillMaxWidth() + ) { + Text( + text = seatSelectionMovieTitle, + style = Typography.head6_b_17, + modifier = Modifier.align(Alignment.CenterHorizontally) + ) + + Spacer(modifier = Modifier.height(16.dp)) + + SeatSelectionChipRow(contents = chipContents) + + Spacer(modifier = Modifier.height(24.dp)) + + Text( + text = "인원선택", + style = Typography.head3_b_14, + color = Black + ) + + Spacer(modifier = Modifier.height(8.dp)) + + Column( + modifier = Modifier.fillMaxWidth(), + verticalArrangement = Arrangement.spacedBy(12.dp) + ) { + StepperRow("일반") + StepperRow("청소년") + StepperRow("경로") + StepperRow("우대") + } + + Spacer(modifier = Modifier.height(32.dp)) + + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.Center + ) { + CgvButton( + text = "뒤로가기", + textStyle = CGVTheme.typography.head6_b_17, + textColor = PrimaryRed400, + borderColor = PrimaryRed400, + horizontalPadding = 48.dp, + verticalPadding = 17.dp, + roundedCornerShape = 12.dp, + onClick = {}, + isBack = true + ) + + Spacer(modifier = Modifier.width(16.dp)) + + CgvButton( + text = "좌석선택", + textStyle = CGVTheme.typography.head6_b_17, + horizontalPadding = 48.dp, + verticalPadding = 17.dp, + roundedCornerShape = 12.dp, + onClick = {}, + enabled = true + ) + } + } + } +} + + +@Preview(showBackground = true) +@Composable +fun SeatSelectionModal1Preview() { + + val ChipContents = listOf( + "2024.11.05 (월)", + "구리", + "10:40 ~ 12:39" + ) + + SeatSelectionModal1( + modifier = Modifier, + seatSelectionMovieTitle = "글래디에이터 2", + chipContents = ChipContents, + onBackClick = { }, + onSeatSelectionClick = { } + ) +} diff --git a/app/src/main/java/org/sopt/cgv/feature/seats/SeatSelectionStepperRow.kt b/app/src/main/java/org/sopt/cgv/feature/seats/SeatSelectionStepperRow.kt new file mode 100644 index 0000000..fadeb74 --- /dev/null +++ b/app/src/main/java/org/sopt/cgv/feature/seats/SeatSelectionStepperRow.kt @@ -0,0 +1,42 @@ +package org.sopt.cgv.feature.seats + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +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.tooling.preview.Preview +import org.sopt.cgv.core.designsystem.theme.Typography + +@Composable +fun StepperRow(label: String) { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = label, + style = Typography.body4_m_15, + color = Color.Black + ) + Stepper( + modifier = Modifier, + initialValue = 0, + onValueChange = { newValue -> + println("$label 인원: $newValue") + } + ) + } +} + +@Preview(showBackground = true) +@Composable +fun StepperRowPreview(){ + StepperRow( + label = "하이" + ) +} diff --git a/app/src/main/java/org/sopt/cgv/feature/seats/SeatSelectionTimeCardRow.kt b/app/src/main/java/org/sopt/cgv/feature/seats/SeatSelectionTimeCardRow.kt new file mode 100644 index 0000000..1256144 --- /dev/null +++ b/app/src/main/java/org/sopt/cgv/feature/seats/SeatSelectionTimeCardRow.kt @@ -0,0 +1,97 @@ +package org.sopt.cgv.feature.seats + +import android.os.Build +import androidx.annotation.RequiresApi +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.lazy.LazyRow +import androidx.compose.foundation.lazy.itemsIndexed +import androidx.compose.runtime.Composable +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import kotlinx.collections.immutable.PersistentList +import kotlinx.collections.immutable.persistentListOf +import org.sopt.cgv.core.designsystem.component.card.CompTimeCard +import java.time.LocalDateTime + +data class TimeCardContent( + val startTime: LocalDateTime, + val endTime: LocalDateTime, + val currentSeats: Int, + val totalSeats: Int, + val isMorning: Boolean, + val isActivated: Boolean +) + +@RequiresApi(Build.VERSION_CODES.O) +@Composable +fun SeatSelectionTimeCardRow( + contents: PersistentList, + modifier: Modifier = Modifier, +) { + var clickedCardIndex = remember { mutableStateOf(Int) } + + LazyRow( + modifier = modifier, + horizontalArrangement = Arrangement.spacedBy(6.dp), + contentPadding = PaddingValues(horizontal = 10.dp) + ) { + itemsIndexed(contents) { index: Int, eachCard -> + CompTimeCard( + modifier = Modifier, + startTime = eachCard.startTime, + endTime = eachCard.endTime, + currentSeats = eachCard.currentSeats, + totalSeats = eachCard.totalSeats, + isMorning = eachCard.isMorning, + isActivated = eachCard.isActivated, + onClick = {} + ) + } + } +} + + +@RequiresApi(Build.VERSION_CODES.O) +@Preview(showBackground = true) +@Composable +fun SeatSelectionTimeCardRowPreview() { + val sampleTimeCardData = persistentListOf( + TimeCardContent( + startTime = LocalDateTime.of(2024, 11, 19, 7, 50), + endTime = LocalDateTime.of(2024, 11, 19, 9, 41), + currentSeats = 185, + totalSeats = 178, + isMorning = true, + isActivated = false, + ), + TimeCardContent( + startTime = LocalDateTime.of(2024, 11, 19, 7, 50), + endTime = LocalDateTime.of(2024, 11, 19, 9, 41), + currentSeats = 185, + totalSeats = 178, + isMorning = true, + isActivated = false, + ), + TimeCardContent( + startTime = LocalDateTime.of(2024, 11, 19, 7, 50), + endTime = LocalDateTime.of(2024, 11, 19, 9, 41), + currentSeats = 185, + totalSeats = 178, + isMorning = true, + isActivated = false, + ), + TimeCardContent( + startTime = LocalDateTime.of(2024, 11, 19, 7, 50), + endTime = LocalDateTime.of(2024, 11, 19, 9, 41), + currentSeats = 185, + totalSeats = 178, + isMorning = false, + isActivated = false, + ) + ) + SeatSelectionTimeCardRow(contents = sampleTimeCardData) +} \ No newline at end of file diff --git a/app/src/main/java/org/sopt/cgv/feature/seats/Stepper.kt b/app/src/main/java/org/sopt/cgv/feature/seats/Stepper.kt new file mode 100644 index 0000000..17a9276 --- /dev/null +++ b/app/src/main/java/org/sopt/cgv/feature/seats/Stepper.kt @@ -0,0 +1,120 @@ +package org.sopt.cgv.feature.seats + +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.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Icon +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.getValue +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import org.sopt.cgv.R +import org.sopt.cgv.core.common.extension.noRippleClickable +import org.sopt.cgv.core.designsystem.theme.Gray100 +import org.sopt.cgv.core.designsystem.theme.Gray700 +import org.sopt.cgv.core.designsystem.theme.Gray800 +import org.sopt.cgv.core.designsystem.theme.Typography + +@Composable +fun Stepper( + modifier: Modifier = Modifier, + initialValue: Int = 0, + onValueChange: (Int) -> Unit +) { + var currentValue by remember { mutableStateOf(initialValue) } + + Row( + modifier = modifier + .size(height = 36.dp, width = 100.dp) + .clip(RoundedCornerShape(8.dp)) + .background(Gray100), + ) { + Row( + modifier = modifier + .fillMaxSize() + .padding(horizontal = 8.dp, vertical = 4.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.SpaceAround, + ){ + // - 버튼 + Box( + modifier = Modifier + .noRippleClickable { + if (currentValue > 0) { + currentValue-- + onValueChange(currentValue) + } + } + .size(20.dp), + contentAlignment = Alignment.Center + ) { + Icon( + painter = painterResource(id = R.drawable.ic_seats_minus), + contentDescription = "인원 감소", + tint = Gray800, + modifier = Modifier.size(20.dp) + ) + } + + // 현재 값 + Box( + modifier = Modifier + .padding(horizontal = 5.dp) + .size(width = 34.dp, height = 28.dp) + .background(Color.White, RoundedCornerShape(8.dp)), + contentAlignment = Alignment.Center + ) { + Text( + text = currentValue.toString(), + style = Typography.head6_b_17, + color = Gray700 + ) + } + + // + 버튼 + Box( + modifier = Modifier + .noRippleClickable { + currentValue++ + onValueChange(currentValue) + } + .size(20.dp), + contentAlignment = Alignment.Center + ) { + Icon( + painter = painterResource(id = R.drawable.ic_seats_plus), + contentDescription = "인원 증가", + tint = Gray800, + modifier = Modifier.size(20.dp) // 아이콘 크기 + ) + } + } + + } +} + +@Preview +@Composable +fun StepperPreview() { + Stepper( + modifier = Modifier, + initialValue = 0, + onValueChange = { newValue -> + println("Stepper value changed: $newValue") + } + ) +} \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_seats_minus.xml b/app/src/main/res/drawable/ic_seats_minus.xml new file mode 100644 index 0000000..8b64710 --- /dev/null +++ b/app/src/main/res/drawable/ic_seats_minus.xml @@ -0,0 +1,12 @@ + + + diff --git a/app/src/main/res/drawable/ic_seats_plus.xml b/app/src/main/res/drawable/ic_seats_plus.xml new file mode 100644 index 0000000..777c87c --- /dev/null +++ b/app/src/main/res/drawable/ic_seats_plus.xml @@ -0,0 +1,18 @@ + + + + diff --git a/app/src/main/res/drawable/ic_time_sun.xml b/app/src/main/res/drawable/ic_time_sun.xml new file mode 100644 index 0000000..e469f01 --- /dev/null +++ b/app/src/main/res/drawable/ic_time_sun.xml @@ -0,0 +1,57 @@ + + + + + + + + + + +