diff --git a/app/src/main/java/com/afs/tutrd/TutrdApp.kt b/app/src/main/java/com/afs/tutrd/TutrdApp.kt index c054157..0e39512 100644 --- a/app/src/main/java/com/afs/tutrd/TutrdApp.kt +++ b/app/src/main/java/com/afs/tutrd/TutrdApp.kt @@ -22,7 +22,6 @@ fun TutrdApp() { val tutrdNavController = rememberTutrdNavController() val navController = tutrdNavController.navController val isVisibleBottomBar = tutrdNavController.isInBottomTabs() - val currentTab = tutrdNavController.mapRouteToTab() TutrdScaffold( diff --git a/app/src/main/java/com/afs/tutrd/component/colordot/ColorDot.kt b/app/src/main/java/com/afs/tutrd/component/colordot/ColorDot.kt new file mode 100644 index 0000000..795e78d --- /dev/null +++ b/app/src/main/java/com/afs/tutrd/component/colordot/ColorDot.kt @@ -0,0 +1,51 @@ +package com.afs.tutrd.component.colordot + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Check +import androidx.compose.material3.Icon +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp + +sealed class DotSize { + data object Big : DotSize() + data object Small : DotSize() +} + + +@Composable +fun ColorDot( + color: Color, + size: DotSize +) { + Icon( + imageVector = Icons.Filled.Check, + contentDescription = "eventDot", + modifier = Modifier + .size(if (size == DotSize.Small) 8.dp else 14.dp) + .background(color, shape = CircleShape), + tint = color + ) +} + +@Preview +@Composable +fun preview() { + Row() { + ColorDot( + Color.Red, + DotSize.Big + ) + ColorDot( + Color.Green, + DotSize.Small + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/afs/tutrd/component/divider/Divider.kt b/app/src/main/java/com/afs/tutrd/component/divider/Divider.kt new file mode 100644 index 0000000..886adf1 --- /dev/null +++ b/app/src/main/java/com/afs/tutrd/component/divider/Divider.kt @@ -0,0 +1,45 @@ +package com.afs.tutrd.component.divider + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +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.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp + +@Composable +fun Divider( + title: String? +) { + Column( + modifier = Modifier, + verticalArrangement = Arrangement.spacedBy(16.dp) + ) { + if (title != null) { + Text( + fontWeight = FontWeight.Bold, + fontSize = 18.sp, + text = title, + ) + } + Box( + modifier = Modifier + .fillMaxWidth() + .height(1.dp) + .background(color = Color(213, 213, 213))) + } +} + +@Preview +@Composable +fun preview() { + Divider(title = "정보") +} \ No newline at end of file diff --git a/app/src/main/java/com/afs/tutrd/component/tooltip/Tooltip.kt b/app/src/main/java/com/afs/tutrd/component/tooltip/Tooltip.kt new file mode 100644 index 0000000..89ee976 --- /dev/null +++ b/app/src/main/java/com/afs/tutrd/component/tooltip/Tooltip.kt @@ -0,0 +1,338 @@ +package com.afs.tutrd.component.tooltip + +import android.view.View +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.padding +import androidx.compose.material.MaterialTheme +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.composed +import androidx.compose.ui.draw.drawBehind +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.Path +import androidx.compose.ui.graphics.Shape +import androidx.compose.ui.layout.LayoutCoordinates +import androidx.compose.ui.layout.boundsInWindow +import androidx.compose.ui.layout.onGloballyPositioned +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.platform.LocalView +import androidx.compose.ui.unit.* +import androidx.compose.ui.window.Popup +import androidx.compose.ui.window.PopupPositionProvider +import androidx.compose.ui.window.PopupProperties +import com.afs.tutrd.theme.Dark +import kotlin.math.roundToInt + +/** + * tooltipContent - Content to display in tooltip. + */ +@Composable +fun TooltipPopup( + modifier: Modifier = Modifier, + requesterView: @Composable (Modifier) -> Unit, + tooltipContent: @Composable () -> Unit, +) { + var isShowTooltip by remember { mutableStateOf(false) } + var position by remember { mutableStateOf(TooltipPopupPosition()) } + + val view = LocalView.current.rootView + + if (isShowTooltip) { + TooltipPopup( + onDismissRequest = { + isShowTooltip = isShowTooltip.not() + }, + position = position, + ) { + tooltipContent() + } + } + requesterView( + modifier + .noRippleClickable { + isShowTooltip = isShowTooltip.not() + } + .onGloballyPositioned { coordinates -> + position = calculateTooltipPopupPosition(view, coordinates) + } + ) +} + +@Composable +fun TooltipPopup( + position: TooltipPopupPosition, + backgroundShape: Shape = MaterialTheme.shapes.medium, + backgroundColor: Color = Dark, + arrowHeight: Dp = 4.dp, + horizontalPadding: Dp = 16.dp, + onDismissRequest: (() -> Unit)? = null, + content: @Composable () -> Unit +) { + var alignment = Alignment.TopCenter + var offset = position.offset + + val horizontalPaddingInPx = with(LocalDensity.current) { + horizontalPadding.toPx() + } + + var arrowPositionX by remember { mutableStateOf(position.centerPositionX) } + + with(LocalDensity.current) { + val arrowPaddingPx = arrowHeight.toPx().roundToInt() * 3 + + when (position.alignment) { + TooltipAlignment.TopCenter -> { + alignment = Alignment.TopCenter + offset = offset.copy( + y = position.offset.y + arrowPaddingPx + ) + } + TooltipAlignment.BottomCenter -> { + alignment = Alignment.BottomCenter + offset = offset.copy( + y = position.offset.y - arrowPaddingPx + ) + } + } + } + + val popupPositionProvider = remember(alignment, offset) { + TooltipAlignmentOffsetPositionProvider( + alignment = alignment, + offset = offset, + horizontalPaddingInPx = horizontalPaddingInPx, + centerPositionX = position.centerPositionX, + ) { position -> + arrowPositionX = position + } + } + + Popup( + popupPositionProvider = popupPositionProvider, + onDismissRequest = onDismissRequest, + properties = PopupProperties(dismissOnBackPress = false), + ) { + BubbleLayout( + modifier = Modifier + .padding(horizontal = horizontalPadding) + .background( + color = backgroundColor, + shape = backgroundShape, + ), + alignment = position.alignment, + arrowHeight = arrowHeight, + arrowPositionX = arrowPositionX, + ) { + content() + } + } +} + +internal class TooltipAlignmentOffsetPositionProvider( + val alignment: Alignment, + val offset: IntOffset, + val centerPositionX: Float, + val horizontalPaddingInPx: Float, + private val onArrowPositionX: (Float) -> Unit, +) : PopupPositionProvider { + + override fun calculatePosition( + anchorBounds: IntRect, + windowSize: IntSize, + layoutDirection: LayoutDirection, + popupContentSize: IntSize + ): IntOffset { + var popupPosition = IntOffset(0, 0) + + // Get the aligned point inside the parent + val parentAlignmentPoint = alignment.align( + IntSize.Zero, + IntSize(anchorBounds.width, anchorBounds.height), + layoutDirection + ) + // Get the aligned point inside the child + val relativePopupPos = alignment.align( + IntSize.Zero, + IntSize(popupContentSize.width, popupContentSize.height), + layoutDirection + ) + + // Add the position of the parent + popupPosition += IntOffset(anchorBounds.left, anchorBounds.top) + + // Add the distance between the parent's top left corner and the alignment point + popupPosition += parentAlignmentPoint + + // Subtract the distance between the children's top left corner and the alignment point + popupPosition -= IntOffset(relativePopupPos.x, relativePopupPos.y) + + // Add the user offset + val resolvedOffset = IntOffset( + offset.x * (if (layoutDirection == LayoutDirection.Ltr) 1 else -1), + offset.y + ) + + popupPosition += resolvedOffset + + val leftSpace = centerPositionX - horizontalPaddingInPx + val rightSpace = windowSize.width - centerPositionX - horizontalPaddingInPx + + val tooltipWidth = popupContentSize.width + val halfPopupContentSize = popupContentSize.center.x + + val fullPadding = horizontalPaddingInPx * 2 + + val maxTooltipSize = windowSize.width - fullPadding + + val isCentralPositionTooltip = halfPopupContentSize <= leftSpace && halfPopupContentSize <= rightSpace + + when { + isCentralPositionTooltip -> { + popupPosition = IntOffset(centerPositionX.toInt() - halfPopupContentSize, popupPosition.y) + val arrowPosition = halfPopupContentSize.toFloat() - horizontalPaddingInPx + onArrowPositionX.invoke(arrowPosition) + } + tooltipWidth >= maxTooltipSize -> { + popupPosition = IntOffset(windowSize.center.x - halfPopupContentSize, popupPosition.y) + val arrowPosition = centerPositionX - popupPosition.x - horizontalPaddingInPx + onArrowPositionX.invoke(arrowPosition) + } + halfPopupContentSize > rightSpace -> { + popupPosition = IntOffset(centerPositionX.toInt(), popupPosition.y) + val arrowPosition = halfPopupContentSize + (halfPopupContentSize - rightSpace) - fullPadding + + onArrowPositionX.invoke(arrowPosition) + } + halfPopupContentSize > leftSpace -> { + popupPosition = IntOffset(0, popupPosition.y) + val arrowPosition = centerPositionX - horizontalPaddingInPx + onArrowPositionX.invoke(arrowPosition) + } + else -> { + val position = centerPositionX + onArrowPositionX.invoke(position) + } + } + + return popupPosition + } +} + +@Composable +fun BubbleLayout( + modifier: Modifier = Modifier, + alignment: TooltipAlignment = TooltipAlignment.TopCenter, + arrowHeight: Dp, + arrowPositionX: Float, + content: @Composable () -> Unit +) { + + val arrowHeightPx = with(LocalDensity.current) { + arrowHeight.toPx() + } + + Box( + modifier = modifier + .drawBehind { + if (arrowPositionX <= 0f) return@drawBehind + + val isTopCenter = alignment == TooltipAlignment.TopCenter + + val path = Path() + + if (isTopCenter) { + val position = Offset(arrowPositionX, 0f) + path.apply { + moveTo(x = position.x, y = position.y) + lineTo(x = position.x - arrowHeightPx, y = position.y) + lineTo(x = position.x, y = position.y - arrowHeightPx) + lineTo(x = position.x + arrowHeightPx, y = position.y) + lineTo(x = position.x, y = position.y) + } + } else { + val arrowY = drawContext.size.height + val position = Offset(arrowPositionX, arrowY) + path.apply { + moveTo(x = position.x, y = position.y) + lineTo(x = position.x + arrowHeightPx, y = position.y) + lineTo(x = position.x, y = position.y + arrowHeightPx) + lineTo(x = position.x - arrowHeightPx, y = position.y) + lineTo(x = position.x, y = position.y) + } + } + + drawPath( + path = path, + color = Dark, + ) + path.close() + } + ) { + content() + } +} + +data class TooltipPopupPosition( + val offset: IntOffset = IntOffset(0, 0), + val alignment: TooltipAlignment = TooltipAlignment.TopCenter, + + val centerPositionX: Float = 0f, +) + +fun calculateTooltipPopupPosition( + view: View, + coordinates: LayoutCoordinates?, +): TooltipPopupPosition { + coordinates ?: return TooltipPopupPosition() + + val visibleWindowBounds = android.graphics.Rect() + view.getWindowVisibleDisplayFrame(visibleWindowBounds) + + val boundsInWindow = coordinates.boundsInWindow() + + val heightAbove = boundsInWindow.top - visibleWindowBounds.top + val heightBelow = visibleWindowBounds.bottom - visibleWindowBounds.top - boundsInWindow.bottom + + val centerPositionX = boundsInWindow.right - (boundsInWindow.right - boundsInWindow.left) / 2 + + val offsetX = centerPositionX - visibleWindowBounds.centerX() + + return if (heightAbove < heightBelow) { + val offset = IntOffset( + y = coordinates.size.height, + x = offsetX.toInt() + ) + TooltipPopupPosition( + offset = offset, + alignment = TooltipAlignment.TopCenter, + centerPositionX = centerPositionX, + ) + } else { + TooltipPopupPosition( + offset = IntOffset( + y = -coordinates.size.height, + x = offsetX.toInt() + ), + alignment = TooltipAlignment.BottomCenter, + centerPositionX = centerPositionX, + ) + } +} + +enum class TooltipAlignment { + BottomCenter, + TopCenter, +} + +fun Modifier.noRippleClickable(onClick: () -> Unit): Modifier = composed { + clickable( + indication = null, + interactionSource = remember { MutableInteractionSource() }) { + onClick() + } +} diff --git a/app/src/main/java/com/afs/tutrd/component/topbar/ClassroomTopBar.kt b/app/src/main/java/com/afs/tutrd/component/topbar/ClassroomTopBar.kt new file mode 100644 index 0000000..7479f5e --- /dev/null +++ b/app/src/main/java/com/afs/tutrd/component/topbar/ClassroomTopBar.kt @@ -0,0 +1,46 @@ +package com.afs.tutrd.component.topbar + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Text +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.afs.tutrd.theme.Heading1 + +@Composable +internal fun ClassroomTopBar( + title: String, + onClickTitle: () -> Unit +) { + Box( + modifier = Modifier + .height(56.dp) + .fillMaxWidth() + .padding(horizontal = 20.dp) + , + contentAlignment = Alignment.CenterStart + ) { + Row( + modifier = Modifier + ) { + Text( + modifier = Modifier, + text = title, + style = Heading1 + ) + } + } +} +@Preview(showBackground = true) +@Composable +private fun previewHomeTopBar() { + ClassroomTopBar(title = "과목 관리") { + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/afs/tutrd/domain/HealthCheck.kt b/app/src/main/java/com/afs/tutrd/domain/HealthCheck.kt deleted file mode 100644 index ad727fa..0000000 --- a/app/src/main/java/com/afs/tutrd/domain/HealthCheck.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.afs.tutrd.domain - -/** - * 디렉토리 초기 구조 잡아 놓기 위해 커밋한 파일입니다 - * - * domain\${featureName} - */ \ No newline at end of file diff --git a/app/src/main/java/com/afs/tutrd/domain/healthCheck/HealthCheckRepository.kt b/app/src/main/java/com/afs/tutrd/domain/healthCheck/HealthCheckRepository.kt deleted file mode 100644 index 0354c55..0000000 --- a/app/src/main/java/com/afs/tutrd/domain/healthCheck/HealthCheckRepository.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.afs.tutrd.domain.healthCheck - -interface HealthCheckRepository { - suspend fun checkHealth(): Result -} \ No newline at end of file diff --git a/app/src/main/java/com/afs/tutrd/navigation/classroom/ClassroomNavigation.kt b/app/src/main/java/com/afs/tutrd/navigation/classroom/ClassroomNavigation.kt index 08ac036..3d8e40a 100644 --- a/app/src/main/java/com/afs/tutrd/navigation/classroom/ClassroomNavigation.kt +++ b/app/src/main/java/com/afs/tutrd/navigation/classroom/ClassroomNavigation.kt @@ -6,14 +6,14 @@ import androidx.navigation.NavGraphBuilder import androidx.navigation.NavOptions import androidx.navigation.compose.composable import com.afs.tutrd.navigation.classroom.screen.Classroom -import com.afs.tutrd.presentation.classroom.ClassroomScreen +import com.afs.tutrd.presentation.classroom.view.ClassroomScreen internal fun NavGraphBuilder.classroomScreen( modifier: Modifier = Modifier ) { composable { - ClassroomScreen(modifier = modifier) + ClassroomScreen() } } diff --git a/app/src/main/java/com/afs/tutrd/navigation/profile/ProfileNavigation.kt b/app/src/main/java/com/afs/tutrd/navigation/profile/ProfileNavigation.kt index 9053458..de49470 100644 --- a/app/src/main/java/com/afs/tutrd/navigation/profile/ProfileNavigation.kt +++ b/app/src/main/java/com/afs/tutrd/navigation/profile/ProfileNavigation.kt @@ -6,13 +6,15 @@ import androidx.navigation.NavGraphBuilder import androidx.navigation.NavOptions import androidx.navigation.compose.composable import com.afs.tutrd.navigation.profile.screen.Profile -import com.afs.tutrd.presentation.profile.ProfileScreen +import com.afs.tutrd.presentation.profile.view.ProfileScreen internal fun NavGraphBuilder.profileScreen( modifier: Modifier = Modifier ) { composable { - ProfileScreen(modifier = modifier) + ProfileScreen( + + modifier = modifier) } } diff --git a/app/src/main/java/com/afs/tutrd/presentation/classroom/view/ClassroomCard.kt b/app/src/main/java/com/afs/tutrd/presentation/classroom/view/ClassroomCard.kt new file mode 100644 index 0000000..964737e --- /dev/null +++ b/app/src/main/java/com/afs/tutrd/presentation/classroom/view/ClassroomCard.kt @@ -0,0 +1,131 @@ +package com.afs.tutrd.presentation.classroom.view + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.material.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.alpha +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.afs.tutrd.R +import com.afs.tutrd.component.colordot.ColorDot +import com.afs.tutrd.component.colordot.DotSize +import com.afs.tutrd.component.tooltip.TooltipPopup +import com.afs.tutrd.theme.Gray45 + +@Composable +fun ClassroomCard() { + Column( + modifier = Modifier + .fillMaxWidth() + .background(color = Color.White), + verticalArrangement = Arrangement.spacedBy(10.dp) + ) + { + Row( + modifier = Modifier.fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically // Aligns all elements vertically at the center + ) { + Box( + modifier = Modifier + .padding(end = 6.dp)) { + ColorDot(color = Color.Blue, size = DotSize.Big) + } + Text( + modifier = Modifier, + fontSize = 18.sp, + fontWeight = FontWeight.SemiBold, + text = "고3 수학" + ) + Box( + modifier = Modifier + .width(17.dp) + .padding(horizontal = 8.dp) + .height(12.dp) + .background(color = Color.Black) + + + ) + Text( + textAlign = TextAlign.Center, + text = "강민석" + + ) + } + Row( + modifier = Modifier, + verticalAlignment = Alignment.CenterVertically + ) { + Text(text = "다음 진도") + Spacer(modifier = Modifier.weight(1f)) + Text(text = "자료구조와 알고리즘-다익스트라 기본개념") //Fixme + } + Row( + modifier = Modifier, + verticalAlignment = Alignment.CenterVertically + ) { + Text(text = "진행 횟수") + TooltipPopup( + modifier = Modifier + .padding(start = 8.dp), + requesterView = { modifier -> + Icon( + modifier = modifier, + painter = painterResource(id = R.drawable.ic_info), + contentDescription = "TooltipPopup", + tint = Gray45, + ) + }, + tooltipContent = { + androidx.compose.material.Text( + modifier = Modifier + .padding(horizontal = 12.dp) + .padding(vertical = 8.dp), + text = "마지막 정산일로부터", + style = TextStyle( + fontSize = 16.sp, + lineHeight = 18.sp, + fontWeight = FontWeight.Medium, + ), + color = Color.White, + ) + } + ) + Spacer(modifier = Modifier.weight(1f)) + Text(text = "4회(총 12회)") + } + Row( + modifier = Modifier.alpha(0.5f), + ) { + Text( + modifier = Modifier, + text = "다음 교육비 납부일") + Spacer(modifier = Modifier.weight(1f)) + Text(text = "2024.08.03 (화)") + } + + } +} + +@Preview +@Composable +fun a() { + ClassroomCard() +} \ No newline at end of file diff --git a/app/src/main/java/com/afs/tutrd/presentation/classroom/view/ClassroomScreen.kt b/app/src/main/java/com/afs/tutrd/presentation/classroom/view/ClassroomScreen.kt new file mode 100644 index 0000000..40972ea --- /dev/null +++ b/app/src/main/java/com/afs/tutrd/presentation/classroom/view/ClassroomScreen.kt @@ -0,0 +1,48 @@ +package com.afs.tutrd.presentation.classroom.view + +import androidx.compose.foundation.gestures.scrollable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import com.afs.tutrd.component.scaffold.TutrdScaffold +import com.afs.tutrd.component.topbar.ClassroomTopBar + +@Composable +fun ClassroomScreen() { + val scrollState = rememberScrollState() + + TutrdScaffold( + topBar = { ClassroomTopBar(title = "과목 관리") { } } + ) { paddingValues -> + Column( + modifier = Modifier + .fillMaxSize() + .padding(paddingValues), + horizontalAlignment = Alignment.CenterHorizontally + + ) { + Column( + modifier = Modifier + .fillMaxSize() + .padding(horizontal = 20.dp) + .verticalScroll(scrollState), + verticalArrangement = Arrangement.spacedBy(20.dp) + + ) { + ClassroomCard() + ClassroomCard() + ClassroomCard() + + } + + } + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/afs/tutrd/presentation/classroom/viewmodel/ClassroomViewModel.kt b/app/src/main/java/com/afs/tutrd/presentation/classroom/viewmodel/ClassroomViewModel.kt new file mode 100644 index 0000000..249e9cb --- /dev/null +++ b/app/src/main/java/com/afs/tutrd/presentation/classroom/viewmodel/ClassroomViewModel.kt @@ -0,0 +1,4 @@ +package com.afs.tutrd.presentation.classroom.viewmodel + +class ClassroomViewModel { +} \ No newline at end of file diff --git a/app/src/main/java/com/afs/tutrd/presentation/home/view/calendar/EventDots.kt b/app/src/main/java/com/afs/tutrd/presentation/home/view/calendar/EventDots.kt index 7d2290d..96b6e9a 100644 --- a/app/src/main/java/com/afs/tutrd/presentation/home/view/calendar/EventDots.kt +++ b/app/src/main/java/com/afs/tutrd/presentation/home/view/calendar/EventDots.kt @@ -19,6 +19,8 @@ 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.afs.tutrd.component.colordot.ColorDot +import com.afs.tutrd.component.colordot.DotSize import com.afs.tutrd.data.model.tutoring.Tutoring @Composable @@ -58,15 +60,7 @@ fun RowOfGrid(rowList: List, columnWidth: Dp) { LazyRow { items(rowList.size) { index -> val item = rowList[index] - Icon( - imageVector = Icons.Filled.Check, - contentDescription = "eventDot", - modifier = Modifier - .size(10.dp) - .padding(2.dp) - .background(item.classProfileColor, shape = CircleShape), - tint = item.classProfileColor - ) + ColorDot(color = item.classProfileColor, size = DotSize.Small) } } diff --git a/app/src/main/java/com/afs/tutrd/presentation/profile/ProfileScreen.kt b/app/src/main/java/com/afs/tutrd/presentation/profile/ProfileScreen.kt deleted file mode 100644 index 9770eca..0000000 --- a/app/src/main/java/com/afs/tutrd/presentation/profile/ProfileScreen.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.afs.tutrd.presentation.profile - -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import com.afs.tutrd.component.scaffold.TutrdScaffold - -@Composable -fun ProfileScreen(modifier: Modifier) { - TutrdScaffold { - Box(modifier = modifier.fillMaxSize()) { - Text(text = "profile screen") - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/afs/tutrd/presentation/profile/view/ProfileScreen.kt b/app/src/main/java/com/afs/tutrd/presentation/profile/view/ProfileScreen.kt new file mode 100644 index 0000000..0f5c33f --- /dev/null +++ b/app/src/main/java/com/afs/tutrd/presentation/profile/view/ProfileScreen.kt @@ -0,0 +1,141 @@ +package com.afs.tutrd.presentation.profile.view + +import androidx.compose.foundation.ScrollState +import androidx.compose.foundation.background +import androidx.compose.foundation.gestures.scrollable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.IntrinsicSize +import androidx.compose.foundation.layout.PaddingValues +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.width +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.Button +import androidx.compose.material3.ButtonColors +import androidx.compose.material3.LocalMinimumInteractiveComponentEnforcement +import androidx.compose.material3.LocalMinimumTouchTargetEnforcement +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton +import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.alpha +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.hilt.navigation.compose.hiltViewModel +import com.afs.tutrd.component.divider.Divider +import com.afs.tutrd.component.scaffold.TutrdScaffold +import com.afs.tutrd.presentation.home.viewmodel.HomeViewModel + +@Composable +fun InfoRow(title: String, value: String, isDimmed: Boolean = false) { + Row( + modifier = Modifier + .fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween + ) { + Text( + fontWeight = FontWeight.Bold, + fontSize = 16.sp, + text = title + ) + Text( + modifier = if (isDimmed) Modifier.alpha(0.5f) else Modifier, + fontSize = 16.sp, + text = value + ) + } +} + +@Composable +fun ProfileTextButton(text: String, onClick: () -> Unit) { + TextButton( + modifier = Modifier + .height(24.dp) + .width(IntrinsicSize.Max), + colors = ButtonColors( + containerColor = Color.Transparent, + contentColor = Color.Black, + disabledContentColor = Color.Gray, + disabledContainerColor = Color.Gray), + contentPadding = PaddingValues(0.dp), + onClick = onClick + ) { + Text( + modifier = Modifier + .fillMaxWidth(), + fontWeight = FontWeight.Bold, + fontSize = 16.sp, + text = text + ) + } +} + +@Composable +fun ProfileScreen( + modifier: Modifier = Modifier, + viewModel: HomeViewModel = hiltViewModel() +) { + + val scrollState = rememberScrollState() + + TutrdScaffold( + topBar = { ProfileTopBar(title = "프로필") } + ) { paddingValues -> + Column( + modifier = modifier + .fillMaxSize() + .padding(paddingValues) + .padding(all = 20.dp) + .verticalScroll(scrollState), + verticalArrangement = Arrangement.spacedBy(32.dp) + ) { + TuteeTutorToggleBar() + Column( + modifier = Modifier + .fillMaxWidth(), + verticalArrangement = Arrangement.spacedBy(16.dp) + ) { + Divider(title = "정보") + InfoRow(title = "이름", value = "정환") + InfoRow(title = "이메일", value = "qwer123@naver.com") + InfoRow(title = "연락처", value = "010-9025-8656") + InfoRow(title = "주요분야", value = "수학, 코딩") + InfoRow(title = "한줄소개", value = "입력해주세요") + } + + Column( + modifier = Modifier + .fillMaxWidth(), + verticalArrangement = Arrangement.spacedBy(16.dp) + ) { + Divider(title = "서비스") + + ProfileTextButton(text = "서비스 이용약관", onClick = { /* TODO */ }) + ProfileTextButton(text = "개인정보 처리방침", onClick = { /* TODO */ }) + ProfileTextButton(text = "오픈소스 라이선스", onClick = { /* TODO */ }) + + } + + Column( + modifier = Modifier + .fillMaxWidth(), + verticalArrangement = Arrangement.spacedBy(16.dp) + ) { + Divider(title = "계정") + InfoRow(title = "아이디", value = "qwer123@naver.com", isDimmed = true) + ProfileTextButton(text = "비밀번호 변경", onClick = { /* TODO */ }) + ProfileTextButton(text = "로그아웃", onClick = { /* TODO */ }) + ProfileTextButton(text = "탈퇴", onClick = { /* TODO */ }) + } + } +}} \ No newline at end of file diff --git a/app/src/main/java/com/afs/tutrd/presentation/profile/view/ProfileTopBar.kt b/app/src/main/java/com/afs/tutrd/presentation/profile/view/ProfileTopBar.kt new file mode 100644 index 0000000..7d43998 --- /dev/null +++ b/app/src/main/java/com/afs/tutrd/presentation/profile/view/ProfileTopBar.kt @@ -0,0 +1,37 @@ +package com.afs.tutrd.presentation.profile.view + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import com.afs.tutrd.theme.Heading1 + +@Composable +internal fun ProfileTopBar( + title: String +) { + Box( + modifier = Modifier + .height(56.dp) + .fillMaxWidth() + .padding(horizontal = 20.dp) + , + contentAlignment = Alignment.CenterStart + ) { + Row( + modifier = Modifier + ) { + Text( + modifier = Modifier, + text = title, + style = Heading1 + ) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/afs/tutrd/presentation/profile/view/TuteeTutorToggleBar.kt b/app/src/main/java/com/afs/tutrd/presentation/profile/view/TuteeTutorToggleBar.kt new file mode 100644 index 0000000..70db66d --- /dev/null +++ b/app/src/main/java/com/afs/tutrd/presentation/profile/view/TuteeTutorToggleBar.kt @@ -0,0 +1,64 @@ +package com.afs.tutrd.presentation.profile.view + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Switch +import androidx.compose.material3.SwitchDefaults +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.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp + +@Composable +fun TuteeTutorToggleBar() { + + val toggleText = "튜티로 전환" //FIXME + var checked by remember { mutableStateOf(false) } + + Row( + modifier = Modifier + .fillMaxWidth() + .height(56.dp) + .background( + color = Color(247, 247, 245), + shape = RoundedCornerShape(8.dp) + ) + .padding(horizontal = 12.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Text( + modifier = Modifier, + fontSize = 16.sp, + fontWeight = FontWeight.Bold, + text = toggleText + ) + Spacer(modifier = Modifier.weight(1f)) + Switch( + colors = SwitchDefaults.colors( + + ), + checked = checked, + onCheckedChange = { checked = it} //FIXME 전환로직 삽입 + ) + } +} +// +//@Preview +//@Composable +//fun preview() { +// TuteeTutorToggleBar() +//} \ No newline at end of file diff --git a/app/src/main/java/com/afs/tutrd/theme/Color.kt b/app/src/main/java/com/afs/tutrd/theme/Color.kt index 5e41b6d..1a3ee07 100644 --- a/app/src/main/java/com/afs/tutrd/theme/Color.kt +++ b/app/src/main/java/com/afs/tutrd/theme/Color.kt @@ -1,3 +1,7 @@ package com.afs.tutrd.theme +import androidx.compose.ui.graphics.Color + // 색상 정의 +val Dark = Color(0xFF4A4D4B) +val Gray45: Color = Color(0xFF838B8E) \ No newline at end of file diff --git a/app/src/main/java/com/afs/tutrd/theme/Theme.kt b/app/src/main/java/com/afs/tutrd/theme/Theme.kt index aa0a375..744ca60 100644 --- a/app/src/main/java/com/afs/tutrd/theme/Theme.kt +++ b/app/src/main/java/com/afs/tutrd/theme/Theme.kt @@ -14,13 +14,10 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalView import androidx.compose.ui.text.PlatformTextStyle import androidx.compose.ui.text.TextStyle -import androidx.compose.ui.text.font.Font -import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.sp import androidx.core.view.WindowCompat -import com.afs.tutrd.R @OptIn(ExperimentalFoundationApi::class) @Composable @@ -59,7 +56,6 @@ object NoRippleTheme : RippleTheme { ) } - val Heading1 = TextStyle( // fontFamily = AppleSDGothicNeo, fontWeight = FontWeight.Bold, diff --git a/app/src/main/res/drawable/ic_info.xml b/app/src/main/res/drawable/ic_info.xml new file mode 100644 index 0000000..42d34b7 --- /dev/null +++ b/app/src/main/res/drawable/ic_info.xml @@ -0,0 +1,26 @@ + + + + +