diff --git a/app/src/main/java/com/paw/key/core/designsystem/component/DogkyFilterBadge.kt b/app/src/main/java/com/paw/key/core/designsystem/component/DogkyFilterBadge.kt new file mode 100644 index 00000000..df189714 --- /dev/null +++ b/app/src/main/java/com/paw/key/core/designsystem/component/DogkyFilterBadge.kt @@ -0,0 +1,63 @@ +package com.paw.key.core.designsystem.component + +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +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.Alignment +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 com.paw.key.core.designsystem.theme.PawKeyTheme + +@Composable +fun DogkyFilterBadge( + location: String, + onLocationClick: () -> Unit, + modifier: Modifier = Modifier, + horizontalPadding: Int = 10, + verticalPadding: Int = 9, +) { + Box( + modifier = modifier + .clip( + RoundedCornerShape(4.dp) + ) + .background( + color = PawKeyTheme.colors.opacity5Primary, + shape = RoundedCornerShape(4.dp) + ) + .border( + width = 1.dp, + color = PawKeyTheme.colors.primary, + shape = RoundedCornerShape(4.dp) + ) + .clickable( + onClick = onLocationClick + ), + contentAlignment = Alignment.Center + ) { + Text( + text = location, + style = PawKeyTheme.typography.buttonSmall, + color = PawKeyTheme.colors.primary, + modifier = Modifier.padding(horizontal = horizontalPadding.dp, vertical = verticalPadding.dp) + ) + } +} + +@Preview +@Composable +private fun RegionBadgePreview() { + PawKeyTheme { + DogkyFilterBadge( + location = "w적음", + onLocationClick = {} + ) + } +} diff --git a/app/src/main/java/com/paw/key/core/designsystem/component/LoadingScreen.kt b/app/src/main/java/com/paw/key/core/designsystem/component/LoadingScreen.kt index 685057cf..c8a143b9 100644 --- a/app/src/main/java/com/paw/key/core/designsystem/component/LoadingScreen.kt +++ b/app/src/main/java/com/paw/key/core/designsystem/component/LoadingScreen.kt @@ -10,7 +10,6 @@ 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 androidx.compose.ui.unit.dp import com.paw.key.core.designsystem.theme.PawKeyTheme @@ -41,4 +40,4 @@ private fun LoadingScreenPreview() { PawKeyTheme { LoadingScreen() } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/paw/key/core/designsystem/theme/Type.kt b/app/src/main/java/com/paw/key/core/designsystem/theme/Type.kt index 2149279c..027b9c64 100644 --- a/app/src/main/java/com/paw/key/core/designsystem/theme/Type.kt +++ b/app/src/main/java/com/paw/key/core/designsystem/theme/Type.kt @@ -151,7 +151,7 @@ class PawKeyTypography internal constructor( buttonSmall: TextStyle = this.buttonSmall, buttonLink: TextStyle = this.buttonLink, - ): PawKeyTypography = PawKeyTypography( + ): PawKeyTypography = PawKeyTypography( head24B, head24Sb, head22B, @@ -454,4 +454,4 @@ fun pawKeyTypography(): PawKeyTypography { letterSpacing = 0.em ), ) -} \ No newline at end of file +} diff --git a/app/src/main/java/com/paw/key/presentation/ui/home/HomeLocationSettingScreen.kt b/app/src/main/java/com/paw/key/presentation/ui/home/HomeLocationSettingScreen.kt index 1f19a583..d9fd1742 100644 --- a/app/src/main/java/com/paw/key/presentation/ui/home/HomeLocationSettingScreen.kt +++ b/app/src/main/java/com/paw/key/presentation/ui/home/HomeLocationSettingScreen.kt @@ -1,3 +1,4 @@ +/* package com.paw.key.presentation.ui.home import androidx.compose.foundation.layout.Box @@ -169,4 +170,4 @@ fun HomeLocationSettingScreen( Spacer(modifier = Modifier.height(46.dp)) } -} \ No newline at end of file +}*/ diff --git a/app/src/main/java/com/paw/key/presentation/ui/home/HomeScreen.kt b/app/src/main/java/com/paw/key/presentation/ui/home/HomeScreen.kt index f7734221..28ef8dff 100644 --- a/app/src/main/java/com/paw/key/presentation/ui/home/HomeScreen.kt +++ b/app/src/main/java/com/paw/key/presentation/ui/home/HomeScreen.kt @@ -1,232 +1,133 @@ package com.paw.key.presentation.ui.home -import android.app.Activity -import androidx.compose.foundation.background -import androidx.compose.foundation.clickable -import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.foundation.layout.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.foundation.lazy.LazyColumn -import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.foundation.lazy.LazyRow +import androidx.compose.foundation.lazy.itemsIndexed +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.SideEffect import androidx.compose.runtime.getValue -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.graphics.toArgb -import androidx.compose.ui.platform.LocalView -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 androidx.core.view.ViewCompat import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.paw.key.R -import com.paw.key.core.designsystem.component.CourseCard +import com.paw.key.core.designsystem.component.LoadingScreen import com.paw.key.core.designsystem.theme.PawKeyTheme -import com.paw.key.core.extension.noRippleClickable -import com.paw.key.presentation.ui.home.component.DaytimeCard +import com.paw.key.core.util.UiState +import com.paw.key.presentation.ui.home.component.HomeRouteItem +import com.paw.key.presentation.ui.home.component.HomeStartWalkingRow import com.paw.key.presentation.ui.home.component.HomeTopBar -import com.paw.key.presentation.ui.home.component.RowCalendar -import com.paw.key.presentation.ui.home.component.SettingButton -import com.paw.key.presentation.ui.home.component.TrackingCard -import com.paw.key.presentation.ui.home.component.WeatherCard +import com.paw.key.presentation.ui.home.component.HomeWalkingInfoHolder +import com.paw.key.presentation.ui.home.model.WalkingRouteUiModel +import com.paw.key.presentation.ui.home.state.HomeState import com.paw.key.presentation.ui.home.viewmodel.HomeViewModel - -@Preview -@Composable -private fun HomeScreenPreview() { - PawKeyTheme { - HomeScreen( - paddingValues = PaddingValues(), - onClickLike = { _, _ -> }, - navigateUp = {}, - navigateNext = {}, - navigateHomeLocationSetting = {}, - viewModel = hiltViewModel() - ) - } -} +import kotlinx.collections.immutable.toImmutableList @Composable fun HomeRoute( paddingValues: PaddingValues, - navigateUp: () -> Unit, - navigateNext: () -> Unit, - navigateHomeLocationSetting: () -> Unit, - modifier: Modifier = Modifier, - viewModel: HomeViewModel = hiltViewModel(), + viewModel: HomeViewModel = hiltViewModel() ) { + val state by viewModel.state.collectAsStateWithLifecycle() + HomeScreen( paddingValues = paddingValues, - navigateUp = navigateUp, - navigateNext = navigateNext, - navigateHomeLocationSetting = navigateHomeLocationSetting, - modifier = modifier, - viewModel = viewModel, - onClickLike = { postId, isLiked -> - viewModel.toggleLike(postId = postId, isLiked = isLiked) - } + state = state ) } @Composable -fun HomeScreen( +private fun HomeScreen( paddingValues: PaddingValues, - navigateUp: () -> Unit, - navigateNext: () -> Unit, - navigateHomeLocationSetting: () -> Unit, - modifier: Modifier = Modifier, - viewModel: HomeViewModel = hiltViewModel(), - onClickLike: (postId: Int, isLiked: Boolean) -> Unit + state: HomeState, ) { - val state by viewModel.state.collectAsStateWithLifecycle() - val view = LocalView.current - val window = (view.context as? Activity)?.window - val postsResult = state.postsResult - - SideEffect { - window?.let { - it.statusBarColor = Color.Black.toArgb() - ViewCompat.getWindowInsetsController(view)?.isAppearanceLightStatusBars = false - } - } - - Column( - modifier = modifier - .padding(paddingValues) - .background(PawKeyTheme.colors.white2) + Column ( + modifier = Modifier .fillMaxSize() + .padding(paddingValues) + .padding(16.dp) + .verticalScroll(rememberScrollState()), + horizontalAlignment = Alignment.CenterHorizontally, ) { HomeTopBar( - location = state.currentRegion.currentName, - onLocationClick = { viewModel.toggleLocationMenu() } + location = "강남구 역삼동", + onLocationClick = {} ) - // 로딩 상태 표시 - if (state.uiState.isLoading) { - Box( - modifier = Modifier.fillMaxSize(), - contentAlignment = Alignment.Center - ) { - CircularProgressIndicator() - } - } else { - LazyColumn( - verticalArrangement = Arrangement.spacedBy(12.dp), - modifier = Modifier - .padding(horizontal = 16.dp) - .background(PawKeyTheme.colors.white2), - ) { - item { - Spacer(modifier = Modifier.height(12.dp)) - WeatherCard( - weathertitle = "35°", - weathersub1 = "35°", - weathersub2 = "21°", - rating = "0", - weatherIcon = R.drawable.ic_home_weather, - ) - } + Spacer(modifier = Modifier.height(24.dp)) - item { - Spacer(modifier = Modifier.height(12.dp)) - Row( - modifier = Modifier - .fillMaxWidth(), - horizontalArrangement = Arrangement.spacedBy(12.dp) - ) { - DaytimeCard( - daytime = "05:06", - daystate = "일출", - modifier = Modifier - .weight(0.3f) - ) + HomeWalkingInfoHolder( + walkingInfo = state.walkingInfo + ) - TrackingCard( - onClick = { navigateNext() }, - modifier = Modifier - .weight(0.7f) - ) - } - } + Spacer(modifier = Modifier.height(24.dp)) - item { RowCalendar(date = "7월") } + HomeStartWalkingRow( + petName = "보리", + onClick = {} + ) - item { - Spacer(modifier = Modifier.height(12.dp)) - Text( - text = stringResource(R.string.ic_home_current_word), - color = PawKeyTheme.colors.black, - style = PawKeyTheme.typography.head18Sb, - ) - } + Spacer(modifier = Modifier.height(32.dp)) - // 에러 상태 표시 - state.uiState.error?.let { error -> - item { - Text( - text = "오류: $error", - color = Color.Red, - modifier = Modifier.padding(16.dp) + Text( + text = "인기있는 산책 루트 추천", + style = PawKeyTheme.typography.header3, + color = PawKeyTheme.colors.contents, + modifier = Modifier.fillMaxWidth(), + textAlign = TextAlign.Start + ) + + Spacer(modifier = Modifier.height(16.dp)) + + when (val uiState = state.walkingPopularData) { + is UiState.Success -> { + LazyRow( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(8.dp) + ) { + itemsIndexed( + items = uiState.data, + key = { _, item -> item.id } + ) { _, item -> + HomeRouteItem( + routeTitle = item.title, + routeDistance = item.distance, + routeTime = item.time, + routeDate = item.date, + routeImage = item.imageUri, + location = item.location ) } } - - item { - CourseCard( - postId = -1, - title = "제목을 입력해주세요", - petName = "반려견 이름", - createdAt = "2025/07/19", - representativeImageUrl = "https://pawkey-bucket.s3.ap-northeast-2.amazonaws.com/route/69a9c758-csnapshot.jpg", - petProfileImageUrl = "", - descriptionTags = listOf("2.2km"), - isLiked = true, - isMine = true, - onClickLike = { isLiked -> - //onClickLike(post.postId, isLiked) - }, - onClickItem = { navigateNext() } - ) - } - - item { Spacer(modifier = Modifier.height(48.dp)) } } + + is UiState.Loading -> {} + is UiState.Empty -> Text("데이터가 없어요") + is UiState.Failure -> Text("로드 실패") } } +} - // 위치 메뉴 오버레이 - if (state.isLocationMenuVisible) { - Box( - modifier = Modifier - .fillMaxSize() - .background(Color.Black.copy(alpha = 0.5f)) - .clickable( - indication = null, - interactionSource = remember { MutableInteractionSource() } - ) { viewModel.toggleLocationMenu() } - ) { - SettingButton( - modifier = Modifier - .padding(top = 43.dp, end = 16.dp) - .noRippleClickable { - viewModel.toggleLocationMenu() - navigateHomeLocationSetting() - } - .align(Alignment.TopEnd), +@Preview +@Composable +private fun HomePreview() { + PawKeyTheme { + HomeScreen( + paddingValues = PaddingValues(), + state = HomeState( + walkingPopularData = UiState.Success(WalkingRouteUiModel.Fake.toImmutableList()) ) - } + ) } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/paw/key/presentation/ui/home/component/DaytimeCard.kt b/app/src/main/java/com/paw/key/presentation/ui/home/component/DaytimeCard.kt deleted file mode 100644 index d0c6c52f..00000000 --- a/app/src/main/java/com/paw/key/presentation/ui/home/component/DaytimeCard.kt +++ /dev/null @@ -1,81 +0,0 @@ -package com.paw.key.presentation.ui.home.component - -import androidx.compose.foundation.background -import androidx.compose.foundation.border -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.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.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.graphics.Color -import androidx.compose.ui.graphics.vector.ImageVector -import androidx.compose.ui.res.vectorResource -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp -import androidx.compose.ui.zIndex -import com.paw.key.R -import com.paw.key.core.designsystem.theme.PawKeyTheme - -@Preview(showBackground = true) -@Composable -private fun PreviewDaytimeCard() { - PawKeyTheme { - DaytimeCard(daytime = "05:06", daystate = "일출") - } -} - -@Composable -fun DaytimeCard( - daytime: String, - daystate: String, - modifier: Modifier = Modifier, -) { - Box( - contentAlignment = Alignment.BottomCenter, - modifier = modifier - .fillMaxWidth() - .height(110.dp) - .background( - color = PawKeyTheme.colors.white1, - shape = RoundedCornerShape(15.dp),) - .clip(RoundedCornerShape(15.dp)), - ) { - Column( - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.spacedBy(31.dp), - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 11.dp) - .padding(bottom = 14.dp) - .zIndex(2F), - ) { - Text( - text = daytime, - color = PawKeyTheme.colors.black, - style = PawKeyTheme.typography.head20B1, - ) - - Text( - text = daystate, - color = PawKeyTheme.colors.black, - style = PawKeyTheme.typography.body16Sb, - ) - } - Icon( - imageVector = ImageVector.vectorResource(R.drawable.img_home_sunrise), - contentDescription = "daytime", - tint = Color.Unspecified, - ) - - } -} \ No newline at end of file diff --git a/app/src/main/java/com/paw/key/presentation/ui/home/component/HistoryCard.kt b/app/src/main/java/com/paw/key/presentation/ui/home/component/HistoryCard.kt deleted file mode 100644 index c6e17b31..00000000 --- a/app/src/main/java/com/paw/key/presentation/ui/home/component/HistoryCard.kt +++ /dev/null @@ -1,173 +0,0 @@ -package com.paw.key.presentation.ui.home.component - -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.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding -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.graphics.Color -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp -import com.paw.key.R -import com.paw.key.core.designsystem.component.SubChip -import com.paw.key.core.designsystem.theme.PawKeyTheme - - -@Preview -@Composable -private fun PreviewHistoryCard() { - PawKeyTheme { - HistoryCard() - } -} - -@Composable -fun HistoryCard( - modifier: Modifier = Modifier, -) { - Box( - modifier = modifier - .fillMaxWidth() - .height(298.dp) - .clip(RoundedCornerShape(12.dp)) - .background( - color = PawKeyTheme.colors.white2, - ), - - ) { - Column { - Box( - modifier = Modifier - .fillMaxWidth() - .height(210.dp) - ) { - Column( - - ) { - HistoryTop() - - Box( - modifier = Modifier - .height(169.dp) - .fillMaxWidth() - .background(color = PawKeyTheme.colors.black) - .padding(top = 114.dp, start = 16.dp) - ) { - InfoColumn( - location = "강남구 역삼동", date = "2025.06.26(금)", time = "23:20-23:30" - ) - } - } - } - Column( - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 16.dp, vertical = 12.dp) - ) { - Row( - horizontalArrangement = Arrangement.spacedBy(6.dp), - ) { - SubChip(text = "2.2km") - - SubChip(text = "30분") - - SubChip(text = "3208걸음") - } - - Row( - horizontalArrangement = Arrangement.spacedBy(6.dp), - ) { - SubChip(text = "자동차 소음이 적어요") - - SubChip(text = "반려견 동반 카페") - } - } - } - } -} - -@Composable -fun HistoryTop( - -) { - Row( - verticalAlignment = Alignment.CenterVertically, - modifier = Modifier - .fillMaxWidth() - .height(41.dp) - .background(color = PawKeyTheme.colors.green400) - .padding(horizontal = 16.dp) - .clip( - RoundedCornerShape( - topStart = 12.dp, topEnd = 12.dp - ) - ), - ) { - Text( - text = "최근산책", - color = PawKeyTheme.colors.white1, - style = PawKeyTheme.typography.body14Sb, - ) - } -} - -@Composable -fun InfoColumn( - location: String, - date: String, - time: String, -) { - Column( - verticalArrangement = Arrangement.Center, - - ) { - Row( - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(6.dp), - - ) { - Icon( - painter = painterResource(id = R.drawable.ic_home_location), - contentDescription = "location", - tint = Color.Unspecified, - ) - - Text( - text = location, - color = PawKeyTheme.colors.white1, - style = PawKeyTheme.typography.body14M, - ) - } - Row( - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(6.dp), - ) { - Icon( - painter = painterResource(id = R.drawable.ic_home_location), - contentDescription = "date", - tint = Color.Unspecified - ) - Text( - text = date, - color = PawKeyTheme.colors.white1, - style = PawKeyTheme.typography.body14M, - ) - Text( - text = time, - color = PawKeyTheme.colors.white1, - style = PawKeyTheme.typography.body14M, - ) - } - } -} diff --git a/app/src/main/java/com/paw/key/presentation/ui/home/component/HistoryChip.kt b/app/src/main/java/com/paw/key/presentation/ui/home/component/HistoryChip.kt deleted file mode 100644 index 1ebfc6ce..00000000 --- a/app/src/main/java/com/paw/key/presentation/ui/home/component/HistoryChip.kt +++ /dev/null @@ -1,43 +0,0 @@ -package com.paw.key.presentation.ui.home.component - -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.tooling.preview.Preview -import androidx.compose.ui.unit.dp -import com.paw.key.core.designsystem.theme.PawKeyTheme - -@Preview(showBackground = true) -@Composable -private fun PreviewHistoryChip() { - PawKeyTheme { - HistoryChip( - text = "4km" - ) - } -} - -@Composable -fun HistoryChip( - text: String, - modifier: Modifier = Modifier, -) { - Box( - modifier - .background( - color = PawKeyTheme.colors.white2, - shape = RoundedCornerShape(4.dp), - ) - .padding(horizontal = 6.dp, vertical = 4.dp), - ) { - Text( - text = text, - color = PawKeyTheme.colors.black, - style = PawKeyTheme.typography.body14M, - ) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/paw/key/presentation/ui/home/component/HomeRouteItem.kt b/app/src/main/java/com/paw/key/presentation/ui/home/component/HomeRouteItem.kt new file mode 100644 index 00000000..23bb89e0 --- /dev/null +++ b/app/src/main/java/com/paw/key/presentation/ui/home/component/HomeRouteItem.kt @@ -0,0 +1,190 @@ +package com.paw.key.presentation.ui.home.component + +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.aspectRatio +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +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.graphics.Color +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.res.vectorResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import coil.compose.AsyncImage +import com.paw.key.R +import com.paw.key.core.designsystem.component.DogkyFilterBadge +import com.paw.key.core.designsystem.theme.PawKeyTheme +import com.paw.key.core.designsystem.theme.PretendardBold + +@Composable +fun HomeRouteItem( + location: String, + routeTitle: String, + routeImage: String, + routeDistance: String, + routeTime: String, + routeDate: String, + modifier: Modifier = Modifier +) { + Column( + modifier = modifier + ) { + Box( + modifier = Modifier + .fillMaxWidth() + .aspectRatio(9f/16f) + .background( + color = PawKeyTheme.colors.gray25, + shape = RoundedCornerShape(8.dp) + ) + .clip(RoundedCornerShape(8.dp)) + ) { + AsyncImage( + model = routeImage, + contentDescription = "routeImage", + contentScale = ContentScale.Crop, + modifier = Modifier.fillMaxSize() + ) + + DogkyFilterBadge( + location = location, + onLocationClick = {}, + horizontalPadding = 6, + verticalPadding = 5, + modifier = Modifier + .align(Alignment.TopStart) + .padding(8.dp) + ) + + IconButton( + onClick = { /*TODO*/ }, + modifier = Modifier + .align(Alignment.TopEnd) + ) { + Icon( + imageVector = ImageVector.vectorResource(R.drawable.ic_heart_default), + contentDescription = "heart", + tint = Color.Unspecified + ) + } + } + + HomeRouteItemInfo( + routeTitle = routeTitle, + routeDistance = routeDistance, + routeTime = routeTime, + routeDate = routeDate + ) + } +} + +@Composable +fun HomeRouteItemInfo( + routeTitle: String, + routeDistance: String, + routeTime: String, + routeDate: String, + modifier: Modifier = Modifier +) { + Column ( + modifier = modifier + .padding( + top = 12.dp, + start = 4.dp, + end = 4.dp + ) + ) { + Text( + text = routeTitle, + style = PawKeyTheme.typography.bodyActive, + fontFamily = PretendardBold, + color = PawKeyTheme.colors.contents + ) + + Spacer(modifier = Modifier.height(4.dp)) + + Text( + text = "현재 거리로부터 ${routeDistance}km", + style = PawKeyTheme.typography.subButtonDefault, + color = PawKeyTheme.colors.defaultMiddle + ) + + Spacer(modifier = Modifier.height(8.dp)) + + Row ( + modifier = Modifier + .fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.SpaceBetween + ) { + HomeIconText( + icon = ImageVector.vectorResource(R.drawable.ic_calendar), + text = routeDate + ) + + HomeIconText( + icon = ImageVector.vectorResource(R.drawable.ic_alarm), + text = "${routeTime}min" + ) + } + } +} + +@Composable +fun HomeIconText( + icon: ImageVector, + text: String, + modifier: Modifier = Modifier +) { + Row ( + modifier = modifier, + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.Center + ) { + Icon( + imageVector = icon, + contentDescription = text, + tint = Color.Unspecified + ) + + Spacer(modifier = Modifier.width(16.dp)) + + Text( + text = text, + style = PawKeyTheme.typography.buttonSmall, + color = PawKeyTheme.colors.defaultMiddle + ) + } +} + +@Preview +@Composable +private fun HomeRouteItemPreview() { + PawKeyTheme { + HomeRouteItem( + routeImage = "", + routeDistance = "10", + routeTime = "10", + routeTitle = "강남구 역삼동", + routeDate = "2025/11/06", + location = "강남구 역삼동" + ) + } + +} diff --git a/app/src/main/java/com/paw/key/presentation/ui/home/component/HomeStartWalkingRow.kt b/app/src/main/java/com/paw/key/presentation/ui/home/component/HomeStartWalkingRow.kt new file mode 100644 index 00000000..4d2262ff --- /dev/null +++ b/app/src/main/java/com/paw/key/presentation/ui/home/component/HomeStartWalkingRow.kt @@ -0,0 +1,78 @@ +package com.paw.key.presentation.ui.home.component + +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.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.paw.key.core.designsystem.theme.PawKeyTheme +import com.paw.key.core.extension.noRippleClickable + +@Composable +fun HomeStartWalkingRow( + petName : String, + onClick: () -> Unit, + modifier: Modifier = Modifier, +) { + Row ( + modifier = modifier + .fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Column { + Text( + text = "${petName}와 함께", + style = PawKeyTheme.typography.bodyActive, + color = PawKeyTheme.colors.contents + ) + + Text( + text = "지금 산책을 시작해보세요!", + style = PawKeyTheme.typography.subButtonDefault, + color = PawKeyTheme.colors.contents + ) + } + + Box( + modifier = Modifier + .clip(RoundedCornerShape(999.dp)) + .background( + color = PawKeyTheme.colors.primary, + shape = RoundedCornerShape(999.dp) + ) + .noRippleClickable(onClick = onClick), + contentAlignment = Alignment.CenterEnd + ) { + Text( + text = "산책 시작", + style = PawKeyTheme.typography.mainButtonDefault, + color = PawKeyTheme.colors.background, + modifier = Modifier + .padding(horizontal = 16.dp, vertical = 10.dp) + ) + } + } +} + +@Preview +@Composable +private fun HomeStartWalkingRowPreview() { + PawKeyTheme { + HomeStartWalkingRow( + petName = "보리", + onClick = {} + ) + } +} diff --git a/app/src/main/java/com/paw/key/presentation/ui/home/component/HomeTopBar.kt b/app/src/main/java/com/paw/key/presentation/ui/home/component/HomeTopBar.kt index 0aaa8e7e..3f74c789 100644 --- a/app/src/main/java/com/paw/key/presentation/ui/home/component/HomeTopBar.kt +++ b/app/src/main/java/com/paw/key/presentation/ui/home/component/HomeTopBar.kt @@ -1,31 +1,20 @@ package com.paw.key.presentation.ui.home.component -import androidx.compose.foundation.background -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.statusBarsPadding -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.Card -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.graphics.vector.ImageVector +import androidx.compose.ui.res.vectorResource import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp import com.paw.key.R +import com.paw.key.core.designsystem.component.DogkyFilterBadge import com.paw.key.core.designsystem.theme.PawKeyTheme -@Preview +@Preview(showBackground = true) @Composable private fun PreviewHomeTopBar() { PawKeyTheme { @@ -43,83 +32,20 @@ fun HomeTopBar( onLocationClick: () -> Unit, modifier: Modifier = Modifier, ) { - Card( + Row ( modifier = modifier - .fillMaxWidth() - .height(46.dp) - .background(color = PawKeyTheme.colors.white1), - shape = RoundedCornerShape( - bottomStart = 15.dp, - bottomEnd = 15.dp, - ), + .fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.SpaceBetween ) { - Row( - verticalAlignment = Alignment.Bottom, - modifier = Modifier - .fillMaxWidth() - .fillMaxHeight() - .background(color = PawKeyTheme.colors.black) - .statusBarsPadding() - .padding(horizontal = 16.dp, vertical = 12.dp), - ) { - DateChip( - text = "D+36", - ) - - Text( - text = stringResource(R.string.ic_home_topbar_text), - modifier = Modifier.padding(start = 4.dp), - color = PawKeyTheme.colors.white1, - style = PawKeyTheme.typography.body14M, - ) - - Spacer(modifier = Modifier.weight(1f)) - - Row( - verticalAlignment = Alignment.CenterVertically, - modifier = Modifier.clickable { onLocationClick() } - ) { - Icon( - painter = painterResource(id = R.drawable.ic_home_location), - contentDescription = null, - tint = Color.Unspecified, - ) - - Text( - text = location, - modifier = Modifier - .padding(horizontal = 2.dp), - color = PawKeyTheme.colors.white1, - style = PawKeyTheme.typography.body14Sb, - ) - - Icon( - painter = painterResource(id = R.drawable.ic_home_under_arrow), - contentDescription = null, - tint = Color.Unspecified, - ) - } - } - } -} + Image( + imageVector = ImageVector.vectorResource(R.drawable.ic_logo), + contentDescription = "logo", + ) -@Composable -private fun DateChip( - text: String, - modifier: Modifier = Modifier, -) { - Box( - modifier - .background( - color = PawKeyTheme.colors.green400, - shape = RoundedCornerShape(15.dp) - ) - .padding(horizontal = 12.dp, vertical = 2.dp) - ) { - Text( - text = text, - color = PawKeyTheme.colors.white1, - style = PawKeyTheme.typography.caption12Sb1 + DogkyFilterBadge( + location = location, + onLocationClick = onLocationClick, ) } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/paw/key/presentation/ui/home/component/HomeWalkingInfoHolder.kt b/app/src/main/java/com/paw/key/presentation/ui/home/component/HomeWalkingInfoHolder.kt new file mode 100644 index 00000000..9b779c4e --- /dev/null +++ b/app/src/main/java/com/paw/key/presentation/ui/home/component/HomeWalkingInfoHolder.kt @@ -0,0 +1,123 @@ +package com.paw.key.presentation.ui.home.component + +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.IntrinsicSize +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxHeight +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.Text +import androidx.compose.material3.VerticalDivider +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.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.paw.key.core.designsystem.theme.PawKeyTheme +import com.paw.key.presentation.ui.home.model.WalkingInfo + +@Composable +fun HomeWalkingInfoHolder( + walkingInfo: WalkingInfo, + modifier: Modifier = Modifier +) { + Row ( + modifier = modifier + .fillMaxWidth() + .height(IntrinsicSize.Min) + .border( + width = 1.dp, + color = PawKeyTheme.colors.primary, + shape = RoundedCornerShape(8.dp) + ) + .clip( + RoundedCornerShape(8.dp) + ) + .background( + color = PawKeyTheme.colors.opacity5Primary, + shape = RoundedCornerShape(8.dp) + ) + .padding(vertical = 16.dp), + horizontalArrangement = Arrangement.SpaceAround, + verticalAlignment = Alignment.CenterVertically + ) { + HomeWalkingInfoHolderItem( + text = "누적 거리", + value = "${walkingInfo.cumulativeDistance} KM", + modifier = Modifier.weight(1f) + ) + + VerticalDivider( + thickness = 2.dp, + color = PawKeyTheme.colors.primary, + modifier = Modifier + .fillMaxHeight() + ) + + HomeWalkingInfoHolderItem( + text = "총 산책 시간", + value = walkingInfo.walkingTime, + modifier = Modifier.weight(1f) + ) + + VerticalDivider( + thickness = 2.dp, + color = PawKeyTheme.colors.primary, + modifier = Modifier + .fillMaxHeight() + ) + + HomeWalkingInfoHolderItem( + text = "산책 횟수", + value = "${walkingInfo.walkingCount} KM", + modifier = Modifier.weight(1f) + ) + } +} + + +@Composable +fun HomeWalkingInfoHolderItem( + text: String, + value : String, + modifier: Modifier = Modifier +) { + Column ( + modifier = modifier, + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy(4.dp) + ) { + Text( + text = text, + style = PawKeyTheme.typography.bodyActive, // Todo: bold로 + color = PawKeyTheme.colors.primary + ) + + Text( + text = value, + style = PawKeyTheme.typography.bodyActive, + color = PawKeyTheme.colors.primary + ) + } +} + +@Preview +@Composable +private fun HomeWalkingInfoHolderPreview() { + PawKeyTheme { + HomeWalkingInfoHolder( + walkingInfo = WalkingInfo( + cumulativeDistance = 10.0, + walkingCount = 1, + walkingTime = "00:00:00", + ), + modifier = Modifier.padding(16.dp) + ) + } +} diff --git a/app/src/main/java/com/paw/key/presentation/ui/home/component/RowCalendar.kt b/app/src/main/java/com/paw/key/presentation/ui/home/component/RowCalendar.kt deleted file mode 100644 index 25406131..00000000 --- a/app/src/main/java/com/paw/key/presentation/ui/home/component/RowCalendar.kt +++ /dev/null @@ -1,172 +0,0 @@ -package com.paw.key.presentation.ui.home.component - -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.size -import androidx.compose.foundation.layout.width -import androidx.compose.foundation.lazy.LazyRow -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp -import com.paw.key.core.designsystem.theme.PawKeyTheme - -@Preview(showBackground = true) -@Composable -private fun PreviewRowCalendar() { - PawKeyTheme { - Column { - RowCalendar(date = "7월") - - CalendarItem( - date = "17", - day = "목", - state = true - ) - - CalendarItem( - date = "20", - day = "일", - state = false, - isToday = true - ) - } - } -} - -@Composable -fun RowCalendar( - date: String, - modifier: Modifier = Modifier, -) { - Box( - modifier = modifier - .fillMaxWidth() - .height(103.dp) - .background( - color = PawKeyTheme.colors.white1, - shape = RoundedCornerShape(size = 16.dp), - ) - .clip(RoundedCornerShape(size = 16.dp)), - ) { - Row( - verticalAlignment = Alignment.CenterVertically, - modifier = Modifier - .padding(horizontal = 18.dp, vertical = 17.dp), - ) { - Text( - text = date, - color = PawKeyTheme.colors.black, - style = PawKeyTheme.typography.head18Sb, - modifier = Modifier - .padding(bottom = 28.dp) - ) - - LazyRow( - horizontalArrangement = Arrangement.spacedBy(2.dp), - modifier = Modifier - .padding(start = 16.dp) - .weight(1f) - ) { - items(7) { index -> - val dates = listOf("14", "15", "16", "17", "18", "19", "20") - val days = listOf("월", "화", "수", "목", "금", "토", "일") - val hasActivity = listOf(true, true, false, true, false, false, false) - val selectedIndex = 3 - val todayIndex = 6 - - CalendarItem( - date = dates[index], - day = days[index], - state = hasActivity[index], - isSelected = index == selectedIndex, - isToday = index == todayIndex, - isAfterSelected = index > selectedIndex && index < todayIndex - ) - } - } - } - } -} - -@Composable -private fun CalendarItem( - date: String, - day: String, - modifier: Modifier = Modifier, - state: Boolean = false, - isSelected: Boolean = false, - isToday: Boolean = false, - isAfterSelected: Boolean = false, -) { - Column( - horizontalAlignment = Alignment.CenterHorizontally, - modifier = modifier - .width(38.dp) - .height(74.dp), - ) { - Box( - contentAlignment = Alignment.Center, - modifier = Modifier - .width(38.dp) - .height(58.dp) - .background( - shape = RoundedCornerShape(8.dp), - color = when { - isSelected -> PawKeyTheme.colors.system_green - else -> Color.Transparent - } - ), - ) { - Column( - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.Center, - ) { - Text( - text = date, - color = when { - isSelected -> PawKeyTheme.colors.white1 - isToday -> Color.Red - isAfterSelected -> PawKeyTheme.colors.black - else -> PawKeyTheme.colors.gray900.copy(alpha = 0.6f) - }, - style = PawKeyTheme.typography.body14R, - ) - - Text( - text = day, - color = when { - isSelected -> PawKeyTheme.colors.white1 - isToday -> Color.Red - isAfterSelected -> PawKeyTheme.colors.black - else -> PawKeyTheme.colors.gray900.copy(alpha = 0.6f) - }, - style = PawKeyTheme.typography.body14R, - ) - } - } - - Spacer(modifier = Modifier.height(4.dp)) - - Box( - modifier = Modifier - .size(6.dp) - .background( - color = if (state) PawKeyTheme.colors.system_green else Color.Transparent, - shape = RoundedCornerShape(50) - ) - ) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/paw/key/presentation/ui/home/component/SettingButton.kt b/app/src/main/java/com/paw/key/presentation/ui/home/component/SettingButton.kt deleted file mode 100644 index 2c850d17..00000000 --- a/app/src/main/java/com/paw/key/presentation/ui/home/component/SettingButton.kt +++ /dev/null @@ -1,64 +0,0 @@ -package com.paw.key.presentation.ui.home.component - -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.fillMaxHeight -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.width -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.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.vector.ImageVector -import androidx.compose.ui.res.vectorResource -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp -import com.paw.key.R -import com.paw.key.core.designsystem.theme.PawKeyTheme - -@Preview(showBackground = true) -@Composable -private fun PreviewSettingButton() { - SettingButton() -} - -@Composable -fun SettingButton( - modifier: Modifier = Modifier, -) { - - Box( - modifier = modifier - .height(64.dp) - .width(140.dp) - .background( - color = PawKeyTheme.colors.white1, shape = RoundedCornerShape(8.dp) - ), - ) { - Row( - horizontalArrangement = Arrangement.spacedBy(6.dp), - verticalAlignment = Alignment.CenterVertically, - modifier = Modifier - .fillMaxWidth() - .fillMaxHeight() - .padding(horizontal = 16.dp, vertical = 20.dp) - ) { - Icon( - imageVector = ImageVector.vectorResource(id = R.drawable.ic_home_setting), - contentDescription = "setting", - ) - - Text( - text = "내 지역 관리", - color = PawKeyTheme.colors.black, - style = PawKeyTheme.typography.body16Sb - ) - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/paw/key/presentation/ui/home/component/TrackingCard.kt b/app/src/main/java/com/paw/key/presentation/ui/home/component/TrackingCard.kt deleted file mode 100644 index cfcfc023..00000000 --- a/app/src/main/java/com/paw/key/presentation/ui/home/component/TrackingCard.kt +++ /dev/null @@ -1,76 +0,0 @@ -package com.paw.key.presentation.ui.home.component - -import androidx.compose.foundation.background -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Box -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.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.graphics.Color -import androidx.compose.ui.graphics.vector.ImageVector -import androidx.compose.ui.res.vectorResource -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp -import com.paw.key.R -import com.paw.key.core.designsystem.theme.PawKeyTheme - - -@Preview -@Composable -private fun PreviewTrackingCard() { - PawKeyTheme { - TrackingCard( - onClick = {} - ) - } -} - -@Composable -fun TrackingCard( - onClick: () -> Unit, - modifier: Modifier = Modifier -) { - Box( - contentAlignment = Alignment.Center, - modifier = modifier - .fillMaxWidth() - .height(110.dp) - .background( - color = PawKeyTheme.colors.black, - shape = RoundedCornerShape(size = 15.dp), - ) - .clip(RoundedCornerShape(size = 15.dp)) - .clickable(onClick = onClick), - ) { - Row( - verticalAlignment = Alignment.CenterVertically, - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 12.dp) - ) { - Text( - text = "산책 시작하기", - color = PawKeyTheme.colors.white1, - style = PawKeyTheme.typography.head22B - ) - - Spacer(modifier = Modifier.weight(1F)) - - Icon( - imageVector = ImageVector.vectorResource(R.drawable.ic_home_startcourse_button), - contentDescription = "tracking", - tint = Color.Unspecified, - ) - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/paw/key/presentation/ui/home/component/WeatherCard.kt b/app/src/main/java/com/paw/key/presentation/ui/home/component/WeatherCard.kt deleted file mode 100644 index 86bbbe2f..00000000 --- a/app/src/main/java/com/paw/key/presentation/ui/home/component/WeatherCard.kt +++ /dev/null @@ -1,108 +0,0 @@ -package com.paw.key.presentation.ui.home.component - -import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.padding -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.graphics.Color -import androidx.compose.ui.graphics.vector.ImageVector -import androidx.compose.ui.res.vectorResource -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp -import com.paw.key.R -import com.paw.key.core.designsystem.theme.PawKeyTheme - -@Preview -@Composable -private fun PreviewWeatherCard() { - PawKeyTheme { - WeatherCard( - weathertitle = "35°", - weathersub1 = "35°", - weathersub2 = "21°", - rating = "0", - weatherIcon = R.drawable.ic_home_weather - ) - } -} - -@Composable -fun WeatherCard( - weathertitle: String, - weathersub1: String, - weathersub2: String, - rating: String, - weatherIcon: Int, - modifier: Modifier = Modifier, -) { - Row( - verticalAlignment = Alignment.CenterVertically, - modifier = modifier - .background( - color = PawKeyTheme.colors.white1, - shape = RoundedCornerShape(size = 15.dp), - ) - .padding(vertical = 12.dp, horizontal = 12.dp), - ) { - Icon( - imageVector = ImageVector.vectorResource(weatherIcon), - contentDescription = "weather", - tint = Color.Unspecified, - ) - - Text( - text = weathertitle, - color = PawKeyTheme.colors.black, - style = PawKeyTheme.typography.head22B.copy( - fontSize = 24.sp - ), - modifier = Modifier.padding(start = 4.dp), - ) - - Row( - verticalAlignment = Alignment.CenterVertically, - modifier = Modifier.padding(start = 8.dp), - ) { - Text( - text = weathersub1, - style = PawKeyTheme.typography.body14R, - ) - - Text( - text = weathersub2, - style = PawKeyTheme.typography.body14R, - color = PawKeyTheme.colors.black.copy(alpha = 0.5f), - modifier = Modifier.padding(start = 6.dp), - ) - } - - Spacer(modifier = Modifier.weight(1F)) - - Icon( - imageVector = ImageVector.vectorResource(id = R.drawable.ic_home_rainrating), - contentDescription = "rainrating", - tint = Color.Unspecified, - ) - - Text( - text = rating, - style = PawKeyTheme.typography.head22B.copy( - fontSize = 24.sp, - ), - ) - - Text( - text = "ml", - style = PawKeyTheme.typography.body14Sb, - modifier = modifier - .padding(top = 4.dp), - ) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/paw/key/presentation/ui/home/model/WalkingInfo.kt b/app/src/main/java/com/paw/key/presentation/ui/home/model/WalkingInfo.kt new file mode 100644 index 00000000..c183334f --- /dev/null +++ b/app/src/main/java/com/paw/key/presentation/ui/home/model/WalkingInfo.kt @@ -0,0 +1,10 @@ +package com.paw.key.presentation.ui.home.model + +import androidx.compose.runtime.Immutable + +@Immutable +data class WalkingInfo( + val cumulativeDistance: Double = 0.0, + val walkingTime : String = "00:00:00", + val walkingCount: Int = 0 +) diff --git a/app/src/main/java/com/paw/key/presentation/ui/home/model/WalkingRouteUiModel.kt b/app/src/main/java/com/paw/key/presentation/ui/home/model/WalkingRouteUiModel.kt new file mode 100644 index 00000000..d69db457 --- /dev/null +++ b/app/src/main/java/com/paw/key/presentation/ui/home/model/WalkingRouteUiModel.kt @@ -0,0 +1,61 @@ +package com.paw.key.presentation.ui.home.model + +data class WalkingRouteUiModel( + val id: Int, + val title: String, + val distance: String, + val time: String, + val date: String, + val imageUri: String, + val location: String +) { + companion object { + val Fake = listOf( + WalkingRouteUiModel( + id = 1, + title = "한강 반포공원 코스", + distance = "3.2km", + time = "45", + date = "2025/11/06", + imageUri = "https://picsum.photos/400/300?random=1", + location = "서울 서초구" + ), + WalkingRouteUiModel( + id = 2, + title = "북서울 꿈의숲 코스", + distance = "2.8km", + time = "38", + date = "2025/11/06", + imageUri = "https://picsum.photos/400/300?random=2", + location = "서울 강북구" + ), + WalkingRouteUiModel( + id = 3, + title = "성수동 카페거리 산책로", + distance = "1.6km", + time = "25", + date = "2025/11/06", + imageUri = "https://picsum.photos/400/300?random=3", + location = "서울 성동구" + ), + WalkingRouteUiModel( + id = 4, + title = "올림픽공원 호수길", + distance = "4.5km", + time = "60", + date = "2025/11/06", + imageUri = "https://picsum.photos/400/300?random=4", + location = "서울 송파구" + ), + WalkingRouteUiModel( + id = 5, + title = "남산 둘레길", + distance = "5.2km", + time = "75", + date = "2025/11/06", + imageUri = "https://picsum.photos/400/300?random=5", + location = "서울 중구" + ) + ) + } +} diff --git a/app/src/main/java/com/paw/key/presentation/ui/home/navigation/HomeLocationSettingNavigation.kt b/app/src/main/java/com/paw/key/presentation/ui/home/navigation/HomeLocationSettingNavigation.kt index 8f7f7151..f8d975f1 100644 --- a/app/src/main/java/com/paw/key/presentation/ui/home/navigation/HomeLocationSettingNavigation.kt +++ b/app/src/main/java/com/paw/key/presentation/ui/home/navigation/HomeLocationSettingNavigation.kt @@ -7,7 +7,6 @@ import androidx.navigation.NavGraphBuilder import androidx.navigation.NavOptions import androidx.navigation.compose.composable import com.paw.key.core.navigation.MainTabRoute -import com.paw.key.presentation.ui.home.HomeLocationSettingRoute import kotlinx.serialization.Serializable @@ -25,15 +24,15 @@ fun NavGraphBuilder.homeLocationSettingNavGraph( modifier: Modifier = Modifier ) { composable { - HomeLocationSettingRoute( + /*HomeLocationSettingRoute( paddingValues = paddingValues, navigateUp = navigateUp, navigateNext = navigateNext, navigateHomeLocationSetting = navigateHomeLocationSetting, modifier = modifier - ) + )*/ } } @Serializable -data object HomeLocationSetting : MainTabRoute \ No newline at end of file +data object HomeLocationSetting : MainTabRoute diff --git a/app/src/main/java/com/paw/key/presentation/ui/home/navigation/HomeNavigation.kt b/app/src/main/java/com/paw/key/presentation/ui/home/navigation/HomeNavigation.kt index 88bd3918..2df475d5 100644 --- a/app/src/main/java/com/paw/key/presentation/ui/home/navigation/HomeNavigation.kt +++ b/app/src/main/java/com/paw/key/presentation/ui/home/navigation/HomeNavigation.kt @@ -26,13 +26,10 @@ fun NavGraphBuilder.homeNavGraph( composable { HomeRoute( paddingValues = paddingValues, - navigateUp = navigateUp, - navigateNext = navigateNext, - navigateHomeLocationSetting = navigateHomeLocationSetting, - modifier = modifier + ) } } @Serializable -data object Home : MainTabRoute \ No newline at end of file +data object Home : MainTabRoute diff --git a/app/src/main/java/com/paw/key/presentation/ui/home/state/HomeContract.kt b/app/src/main/java/com/paw/key/presentation/ui/home/state/HomeContract.kt index b2f934de..5f77d848 100644 --- a/app/src/main/java/com/paw/key/presentation/ui/home/state/HomeContract.kt +++ b/app/src/main/java/com/paw/key/presentation/ui/home/state/HomeContract.kt @@ -1,84 +1,17 @@ - package com.paw.key.presentation.ui.home.state -import androidx.compose.runtime.Immutable -import com.paw.key.core.util.PreferenceDataStore -import com.paw.key.domain.model.entity.archivedlist.ArchivedListEntity -import com.paw.key.domain.model.entity.list.ListEntity -import kotlinx.coroutines.flow.first -import kotlinx.coroutines.runBlocking - -class HomeContract { - - @Immutable - data class HomeState( - val isLocationMenuVisible: Boolean = false, - val postsResult: ListEntity? = null, - val selectedLocation: LocationInfo = LocationInfo(), - val courseList: List = emptyList(), - val uiState: HomeUiState = HomeUiState(), - val currentRegion: CurrentRegionInfo = CurrentRegionInfo() - ) - - @Immutable - data class CurrentRegionInfo( - val currentId: Int = 0, - val currentName: String = "" - ) - - @Immutable - data class LocationInfo( - val selectedGuId: Int = 0, - val selectedDongId: Int = 0, - val selectedGu: String = "", - val selectedDong: String = "" - ) { - val displayLocation: String - get() = when { - // 구/동이 모두 선택된 경우 - selectedGu.isNotEmpty() && selectedDong.isNotEmpty() -> { - "$selectedGu $selectedDong" - } - // 구만 선택된 경우 - selectedGu.isNotEmpty() -> { - selectedGu - } - // 아무것도 선택되지 않은 경우 - activeRegion 사용 - else -> { - try { - // 코루틴 블로킹 호출 (UI에서는 이미 로드된 상태여야 함) - runBlocking { - val activeRegion = PreferenceDataStore.getActiveRegion().first() - activeRegion.ifEmpty { "위치를 선택해주세요" } - } - } catch (e: Exception) { - "위치를 선택해주세요" - } - } - } - } - - @Immutable - data class HomeUiState( - val isVisible: Boolean = false, - val isLoading: Boolean = false, - val error: String? = null - ) - - // 액션들을 정의하는 sealed class - sealed class HomeAction { - object ToggleLocationMenu : HomeAction() - data class SelectGu(val guName: String, val guId: Int) : HomeAction() - data class SelectDong(val dongName: String, val dongId: Int) : HomeAction() - data class ToggleLike(val postId: Int, val isLiked: Boolean) : HomeAction() - object RefreshPosts : HomeAction() - object ClearError : HomeAction() - } - - // 사이드 이펙트를 정의하는 sealed class - sealed class HomeSideEffect { - object NavigateToLocationSetting : HomeSideEffect() - data class ShowError(val message: String) : HomeSideEffect() - data class ShowToast(val message: String) : HomeSideEffect() - } -} \ No newline at end of file +import com.paw.key.core.util.UiState +import com.paw.key.presentation.ui.home.model.WalkingInfo +import com.paw.key.presentation.ui.home.model.WalkingRouteUiModel +import kotlinx.collections.immutable.ImmutableList + +data class HomeState( + val walkingPopularData : UiState> = UiState.Loading, + val walkingInfo: WalkingInfo = WalkingInfo() +) + +sealed interface HomeSideEffect { + data class ShowToast(val message: String) : HomeSideEffect + data class ShowSnackBar(val message: String) : HomeSideEffect + data class NavigateToDetail(val id: Int) : HomeSideEffect +} diff --git a/app/src/main/java/com/paw/key/presentation/ui/home/viewmodel/HomeViewModel.kt b/app/src/main/java/com/paw/key/presentation/ui/home/viewmodel/HomeViewModel.kt index 46626b40..0f276dbf 100644 --- a/app/src/main/java/com/paw/key/presentation/ui/home/viewmodel/HomeViewModel.kt +++ b/app/src/main/java/com/paw/key/presentation/ui/home/viewmodel/HomeViewModel.kt @@ -1,214 +1,49 @@ package com.paw.key.presentation.ui.home.viewmodel -import DistrictDto -import android.util.Log import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import com.paw.key.core.util.PreferenceDataStore -import com.paw.key.domain.repository.home.RegionCurrentRepository -import com.paw.key.domain.repository.onboarding.OnboardingRegionRepository -import com.paw.key.presentation.ui.home.state.HomeContract +import com.paw.key.core.util.UiState +import com.paw.key.presentation.ui.home.model.WalkingRouteUiModel +import com.paw.key.presentation.ui.home.state.HomeSideEffect +import com.paw.key.presentation.ui.home.state.HomeState import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.collections.immutable.toImmutableList +import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.asStateFlow -import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.update -import kotlinx.coroutines.launch -import timber.log.Timber import javax.inject.Inject @HiltViewModel class HomeViewModel @Inject constructor( - private val regionRepository: OnboardingRegionRepository, - private val regionCurrentRepository: RegionCurrentRepository, -) : ViewModel() { +): ViewModel() { + private val _state = MutableStateFlow(HomeState()) + val state = _state.asStateFlow() - private val _state = MutableStateFlow(HomeContract.HomeState()) - val state: StateFlow = _state.asStateFlow() - - private val _regionList = MutableStateFlow>(emptyList()) - val regionList: StateFlow> = _regionList.asStateFlow() - - val userId = PreferenceDataStore.getUserId() + private val _sideEffect = MutableSharedFlow() + val sideEffect = _sideEffect.asSharedFlow() init { - fetchRegion() - regionCurrent() - } - - fun toggleLocationMenu() { - _state.update { currentState -> - currentState.copy( - isLocationMenuVisible = !currentState.isLocationMenuVisible + _state.update { + it.copy( + walkingPopularData = UiState.Success(WalkingRouteUiModel.Fake.toImmutableList()) ) } } - fun onGuSelected(guName: String, guId: Int) { - viewModelScope.launch { - try { - // DataStore에 구 정보 저장 - PreferenceDataStore.saveGuInfo(guId, guName) - - // 상태 업데이트 - _state.update { currentState -> - currentState.copy( - selectedLocation = currentState.selectedLocation.copy( - selectedGu = guName, - selectedGuId = guId, - // 구를 새로 선택하면 기존 동 선택 초기화 - selectedDong = "", - selectedDongId = 0 - ), - // 구 선택 후 메뉴 닫기 - isLocationMenuVisible = false - ) - } - Log.d("HomeViewModel", "구 선택 완료: $guName (ID: $guId)") - } catch (e: Exception) { - Log.e("HomeViewModel", "구 선택 저장 실패: ${e.message}") - } - } - } - - fun onDongSelected(dongName: String, dongId: Int) { - viewModelScope.launch { - try { - // 현재 구 정보와 함께 전체 위치 정보 저장 - val currentLocation = _state.value.selectedLocation - PreferenceDataStore.saveLocationInfo( - guId = currentLocation.selectedGuId, - dongId = dongId, - guName = currentLocation.selectedGu, - dongName = dongName + /*fun onEvent(event: HomeEvent) { + when (event) { + is HomeEvent.OnWalkingInfoChanged -> { + _state.value = _state.value.copy( + walkingInfo = event.walkingInfo ) - - // 상태 업데이트 - _state.update { currentState -> - currentState.copy( - selectedLocation = currentState.selectedLocation.copy( - selectedDong = dongName, - selectedDongId = dongId - ) - ) - } - Timber.d("HomeViewmodel", "동 선택 완료: $dongName (ID: $dongId)") - } catch (e: Exception) { - Timber.e("HomeViewmodel", "동 선택 저장 실패: ${e.message}") - } - - } - } - - private fun regionCurrent() { - _state.update { it.copy(uiState = it.uiState.copy(isLoading = true)) } - - viewModelScope.launch { - try { - val result = regionCurrentRepository.regionCurrent(userId.first()) - result.onSuccess { response -> - Log.d("HomeViewModel", "RegionCurrent 성공: ${response.fullRegionName}") - PreferenceDataStore.saveActiveRegion(response.fullRegionName) - Log.d("HomeViewModel", "activeRegion 저장 완료: ${response.fullRegionName}") - _state.update { currentState -> - currentState.copy( - currentRegion = HomeContract.CurrentRegionInfo( - currentId = response.currentRegionId, - currentName = response.fullRegionName - ), - uiState = currentState.uiState.copy( - isLoading = false, - error = null - ) - ) - } - }.onFailure { exception -> - Log.e("HomeViewModel", "RegionCurrent 실패: ${exception.message}") - _state.update { currentState -> - currentState.copy( - uiState = currentState.uiState.copy( - isLoading = false, - error = exception.message - ) - ) - } - } - } catch (e: Exception) { - Log.e("HomeViewModel", "RegionCurrent Exception: ${e.message}") - _state.update { currentState -> - currentState.copy( - uiState = currentState.uiState.copy( - isLoading = false, - error = e.message - ) - ) - } } - } - } - private fun fetchRegion() { - _state.update { it.copy(uiState = it.uiState.copy(isLoading = true)) } + is HomeEvent.OnWalkingPopularDataChanged -> { - viewModelScope.launch { - try { - val result = regionRepository.getOnboardingRegion(userId.first()) - result.onSuccess { response -> - Log.d("HomeViewModel", "Region loaded: ${response.data.districtDtos.size}") - _regionList.value = response.data.districtDtos - _state.update { - it.copy( - uiState = it.uiState.copy( - isLoading = false, - error = null - ) - ) - } - }.onFailure { exception -> - Log.e("HomeViewModel", "구/동 가져오기 실패: ${exception.message}") - _state.update { - it.copy( - uiState = it.uiState.copy( - isLoading = false, - error = exception.message - ) - ) - } - } - } catch (e: Exception) { - Log.e("HomeViewModel", "fetchRegion Exception: ${e.message}") - _state.update { - it.copy( - uiState = it.uiState.copy( - isLoading = false, - error = e.message - ) - ) - } } - } - } - - fun toggleLike(postId: Int, isLiked: Boolean) { - viewModelScope.launch { - _state.update { currentState -> - val updatedPostsResult = currentState.postsResult?.let { postsResult -> - postsResult.copy( - posts = postsResult.posts.map { post -> - if (post.postId == postId) { - post.copy(isLike = isLiked) - } else { - post - } - } - ) - } - currentState.copy( - postsResult = updatedPostsResult - ) - } + else -> {} } - } -} \ No newline at end of file + }*/ +} diff --git a/app/src/main/java/com/paw/key/presentation/ui/login/LoginScreen.kt b/app/src/main/java/com/paw/key/presentation/ui/login/LoginScreen.kt index ec8f8c10..fdc34cc9 100644 --- a/app/src/main/java/com/paw/key/presentation/ui/login/LoginScreen.kt +++ b/app/src/main/java/com/paw/key/presentation/ui/login/LoginScreen.kt @@ -3,6 +3,7 @@ package com.paw.key.presentation.ui.login import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.Image import androidx.compose.foundation.background +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -41,6 +42,7 @@ import com.paw.key.core.util.PreferenceDataStore import com.paw.key.presentation.ui.login.component.LoginSocialButton import com.paw.key.presentation.ui.login.viewmodel.LoginViewModel import kotlinx.coroutines.launch +import timber.log.Timber @Composable fun LoginRoute( @@ -124,7 +126,9 @@ fun LoginScreen( imageVector = ImageVector.vectorResource(R.drawable.ic_login_title_logo), contentDescription = stringResource(id = R.string.ic_login_main_logo), tint = PawKeyTheme.colors.primary, - modifier = Modifier.padding(start = 19.dp) + modifier = Modifier + .clickable(onClick = navigateHome) + .padding(start = 19.dp) ) Text( @@ -160,6 +164,7 @@ fun LoginScreen( logo = R.drawable.ic_login_google, loginText = stringResource(R.string.ic_login_google), onClick = { + Timber.e("onClick LoginSocialButton") viewModel.onGoogleSignIn( context = context, onSuccess = navigateHome @@ -207,4 +212,4 @@ private fun PreviewLoginScreen() { isLoginFormValid = true, ) } -} \ No newline at end of file +} diff --git a/app/src/main/res/drawable/ic_alarm.xml b/app/src/main/res/drawable/ic_alarm.xml new file mode 100644 index 00000000..c6b99b22 --- /dev/null +++ b/app/src/main/res/drawable/ic_alarm.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/src/main/res/drawable/ic_calendar.xml b/app/src/main/res/drawable/ic_calendar.xml new file mode 100644 index 00000000..868e66d2 --- /dev/null +++ b/app/src/main/res/drawable/ic_calendar.xml @@ -0,0 +1,13 @@ + + + + diff --git a/app/src/main/res/drawable/ic_logo.xml b/app/src/main/res/drawable/ic_logo.xml new file mode 100644 index 00000000..5f9f863d --- /dev/null +++ b/app/src/main/res/drawable/ic_logo.xml @@ -0,0 +1,22 @@ + + + + + + + +