Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature/#11] 프로필 페이지 & 좋아요 목록 페이지 구현 #15

Merged
merged 9 commits into from
Nov 7, 2024
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.hackathon.alddeul_babsang.domain.entity

data class BabsangListEntity(
val id: Long,
val avatar: String? = null,
val name: String,
val codeName: String,
val address: String,
val phone: String,
val favorite: Boolean = false,
)
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,17 @@ package com.hackathon.alddeul_babsang.presentation.profile.navigation

import androidx.navigation.NavGraphBuilder
import androidx.navigation.compose.composable
import com.hackathon.alddeul_babsang.presentation.profile.screen.ProfileLikeListRoute
import com.hackathon.alddeul_babsang.presentation.profile.screen.ProfileRoute


fun NavGraphBuilder.profileNavGraph(
navigator: ProfileNavigator
) {
composable(route = "profile") {
ProfileRoute(navigator = navigator)
}
composable(route = "profileLikeList") {
ProfileLikeListRoute(navigator = navigator)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,21 @@ import androidx.navigation.NavController
class ProfileNavigator(
val navController: NavController
) {

fun navigateDetail(id: Long) {
navController.navigate("detail?id=$id")
}

fun navigateBack() {
navController.popBackStack()
}

fun navigateLogin() {
navController.navigate("login") {
popUpTo("profile") { inclusive = true }
launchSingleTop = true
}

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
package com.hackathon.alddeul_babsang.presentation.profile.screen

import androidx.compose.foundation.Image
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.Column
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.width
import androidx.compose.foundation.shape.RoundedCornerShape
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.draw.clip
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.navigation.compose.rememberNavController
import coil.compose.AsyncImage
import com.hackathon.alddeul_babsang.R
import com.hackathon.alddeul_babsang.core_ui.theme.AlddeulBabsangTheme
import com.hackathon.alddeul_babsang.core_ui.theme.Gray300
import com.hackathon.alddeul_babsang.core_ui.theme.Orange700
import com.hackathon.alddeul_babsang.core_ui.theme.Orange800
import com.hackathon.alddeul_babsang.core_ui.theme.Orange900
import com.hackathon.alddeul_babsang.core_ui.theme.body2Regular
import com.hackathon.alddeul_babsang.core_ui.theme.body4Regular
import com.hackathon.alddeul_babsang.core_ui.theme.head4Bold
import com.hackathon.alddeul_babsang.domain.entity.BabsangListEntity
import com.hackathon.alddeul_babsang.presentation.profile.navigation.ProfileNavigator

@Composable
fun LikeItem(
navigator: ProfileNavigator,
data: BabsangListEntity
) {

var isFavorite by remember { mutableStateOf(data.favorite ?: false) }

// 클릭할 때마다 favorite 값 토글
val heartIconId = if (isFavorite) {
R.drawable.ic_heart_red
} else {
R.drawable.ic_heart_white
}


Column(
modifier = Modifier
.fillMaxWidth()
.border(
width = 1.dp,
color = Orange700,
shape = RoundedCornerShape(14.dp)
)
.height(240.dp)
.clickable(onClick = {
navigator.navigateDetail(data.id)
})
) {
Box(
modifier = Modifier
.fillMaxWidth()
.height(140.dp)
.clip(RoundedCornerShape(topStart = 14.dp, topEnd = 14.dp))
) {
// AsyncImage 로드
LoadImageWithPlaceholder(data.codeName, data.avatar)

Image(
painter = painterResource(heartIconId),
contentDescription = null,
modifier = Modifier
.padding(end = 10.dp, top = 10.dp)
.align(Alignment.TopEnd) // Box 내에서 오른쪽 끝으로 배치
.clickable {
// 클릭 시 좋아요 상태를 토글
isFavorite = !isFavorite
}
)
}

Spacer(modifier = Modifier.height(15.dp))

Row {
Text(
text = data.name,
style = head4Bold,
color = Orange900,
modifier = Modifier.padding(start = 20.dp)
)

Spacer(modifier = Modifier.width(15.dp))

Text(
text = data.codeName,
style = body2Regular,
color = Orange800,
modifier = Modifier
.align(Alignment.Bottom)
.padding(bottom = 3.dp)
)
}

Spacer(modifier = Modifier.height(12.dp))

Text(
text = data.address,
style = body4Regular,
color = Gray300,
modifier = Modifier.padding(start = 20.dp)
)

Spacer(modifier = Modifier.height(7.dp))

Text(
text = data.phone,
style = body4Regular,
color = Gray300,
modifier = Modifier.padding(start = 20.dp)
)
}
}

@Composable
fun LoadImageWithPlaceholder(codeName: String, imageUrl: String?) {
val imageId = when (codeName) {
"경양식/일식" -> R.drawable.ic_japanese_food
"한식" -> R.drawable.ic_korean_food
"중식" -> R.drawable.ic_chinese_food
else -> R.drawable.ic_etc_food
}


Box(
modifier = Modifier
.fillMaxWidth()
.fillMaxHeight()
.background(color = Orange700) // 배경색 설정
) {
if (imageUrl.isNullOrEmpty()) {
// imageUrl이 null이나 empty일 경우 대체 이미지 표시
Image(
painter = painterResource(id = imageId), // 대체 이미지
contentDescription = null,
modifier = Modifier
.fillMaxWidth()
.fillMaxHeight()
.padding(vertical = 15.dp)
)
} else {
// imageUrl이 null이 아니면 AsyncImage로 비동기 이미지 로드
AsyncImage(
model = imageUrl,
contentDescription = null,
placeholder = painterResource(id = imageId),
contentScale = ContentScale.Crop, // 이미지 비율 유지, 크기 확대 또는 자르기
modifier = Modifier
.fillMaxWidth() // 가로는 꽉 차게
.fillMaxHeight() // 세로도 꽉 차게
.clip(RoundedCornerShape(topStart = 14.dp, topEnd = 14.dp))

)

}
}
}

@Preview(showBackground = true)
@Composable
fun LikeItemPreview() {
val navController = rememberNavController()
val navigator = ProfileNavigator(navController)

AlddeulBabsangTheme {
LikeItem(
navigator = navigator,
data = BabsangListEntity(
id = 1,
avatar = null,
name = "송이네 밥상",
codeName = "경양식/일식",
address = "서울특별시 용산구 청파동 11",
phone = "02-210-0220",
favorite = true
)
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package com.hackathon.alddeul_babsang.presentation.profile.screen


import androidx.lifecycle.ViewModel
import com.hackathon.alddeul_babsang.domain.entity.BabsangListEntity
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject

@HiltViewModel
class BabsangListViewModel @Inject constructor() : ViewModel() {


val mockLikeList = listOf(
BabsangListEntity(
id = 1,
avatar = null,
name = "송이네 밥상",
codeName = "기타외식업",
address = "서울특별시 용산구 청파동 81",
phone = "02-210-0120",
favorite = true
),
BabsangListEntity(
id = 2,
avatar = null,
name = "송이네 일식",
codeName = "경양식/일식",
address = "서울특별시 용산구 청파동 11",
phone = "02-210-0220",
favorite = true
),
BabsangListEntity(
id = 3,
avatar = null,
name = "송이네 한식",
codeName = "한식",
address = "서울특별시 용산구 청파동 31",
phone = "02-223-0220",
favorite = true
),
BabsangListEntity(
id = 4,
avatar = null,
name = "송이네 중식",
codeName = "중식",
address = "서울특별시 용산구 청파동 31",
phone = "02-223-0220",
favorite = true
),
BabsangListEntity(
id = 4,
avatar = "https://avatars.githubusercontent.com/u/166610834?s=400&u=568eacc2e4696d563a4fd732c148edba2196e4f6&v=4",
name = "송이네 밥상",
codeName = "중식",
address = "서울특별시 용산구 청파동 31",
phone = "02-223-0220",
favorite = true
)

)
}
Loading
Loading