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

Feat/#57-게시글 목록 조회 UI를 구현한다 #60

Merged
merged 23 commits into from
Mar 24, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
b4868ff
feat : 게시글 등록 모듈 생성
chws0508 Mar 8, 2024
27c6192
feat : 게시글 등록 기능 UI 구현 완료
chws0508 Mar 8, 2024
038eb3c
feat : UI기능 전까지 완료
chws0508 Mar 8, 2024
16fadaa
feat : 커스텀 갤러리 기능 구현
chws0508 Mar 11, 2024
10a6e5f
feat : 갤러리에서 선택한 이미지를 게시글에서 받도록 구현
chws0508 Mar 11, 2024
d7c8136
feat : 게시글 등록 API 연동 구현
chws0508 Mar 11, 2024
a09216d
feat : StringResource 리팩토링
chws0508 Mar 12, 2024
5f024c0
feat : Dependency Graph 모듈 볼수 있는 플러그인 추가
chws0508 Mar 12, 2024
f206048
feat : 화면 회전시 앱이 안보이는 버그 수정
chws0508 Mar 13, 2024
0454238
feat : GetAlbumImagesUseCase로 네이밍 수정
chws0508 Mar 13, 2024
1e7f6a7
feat : GetAlbumImagesUseCase에서 ImagePagingInfo를 주도록 변경
chws0508 Mar 14, 2024
92d3e28
feat : GalleryViewModel Test 작성
chws0508 Mar 14, 2024
700f690
feat : 앱 난독화 적용
chws0508 Mar 15, 2024
7929d99
test : RegisterPostViewModel 테스트 작성
chws0508 Mar 15, 2024
b969197
feat : core-ui 모듈 추가 및 PostTopicUiState core-ui로 이동
chws0508 Mar 18, 2024
4a19142
refactor : Rebase 충돌 수정
chws0508 Mar 18, 2024
6b02cfe
refactor : 모듈을 post에서 postList로 수정
chws0508 Mar 18, 2024
29611b1
refactor : material3 버젼 업
chws0508 Mar 18, 2024
419f456
feat : 게시글 목록 화면 탭 UI 구현
chws0508 Mar 18, 2024
94865c7
feat : Tab에 viewModel 상태 적용
chws0508 Mar 18, 2024
5940514
feat : 게시글 목록 UI 구현 완료
chws0508 Mar 18, 2024
2153afc
feat : Date 계산 로직 도메인으로 이동
chws0508 Mar 19, 2024
022192c
feat : 사진 변경사항 적용
chws0508 Mar 24, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ dependencies {

"implementation"(libs.findLibrary("androidx.activity.compose").get())
"implementation"(libs.findLibrary("androidx.compose.material3").get())
"implementation"(libs.findLibrary("androidx.constraintlayout").get())
"implementation"(libs.findLibrary("androidx.compose.ui").get())
"implementation"(libs.findLibrary("androidx.compose.ui.tooling.preview").get())
"implementation"(libs.findLibrary("androidx.lifecycle.runtimeCompose").get())
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.withpeace.withpeace.core.designsystem.ui

import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.clickable
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.withpeace.withpeace.core.designsystem.theme.WithpeaceTheme

@Composable
fun WithpeaceCard(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

어디에 쓰이는 카드인가요?!
캡쳐 해주시면 감사합니다

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

스크린샷 2024-03-19 오후 3 38 45
게시글 내용을 감싸는 테두리 라고 생각하시면 될 것 같습니다! 보통 저 테두리는 공통으로 쓰이기 때문에 designSystem으로 빼놨습니다

modifier: Modifier = Modifier,
content: @Composable () -> Unit,
) {
Card(
modifier = modifier,
shape = RoundedCornerShape(5.dp),
border = BorderStroke(width = 1.dp, color = WithpeaceTheme.colors.SystemGray2),
colors = CardDefaults.cardColors(
containerColor = WithpeaceTheme.colors.SystemWhite,
),
) {
content()
}
}

@Preview(showBackground = true)
@Composable
private fun WithpeaceCardPreview() {
WithpeaceTheme {
WithpeaceCard {
Text("haha")
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.withpeace.withpeace.core.ui

import android.content.Context
import java.time.Duration
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter

fun LocalDateTime.toRelativeString(context: Context): String {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

해당 코드는 View에서만 사용되는게 맞을까요?!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

단위를 구분하는건 domain이고 글자를 표시하는 건 view라고 생각합니다!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저도 어디에 위치해야 할지 조금 애매했는데요, isLessThanOneDay 같은 함수들을 Post 도메인 로직으로 옮기는게 좋아보일까요?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

domain 사용성을 위해서 옮기는 것도 좋아보입니다! Date 관련 도메인 로직이 될 것 같은데 어떠신가요?!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PostDate라는 도메인 모델에 적용하고, Post객체가 PostDate를 사용하게끔 하면 될 것 같습니다!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

좋습니다! 👍 🥇 💯

val currentTime = LocalDateTime.now()
val duration = Duration.between(this, currentTime)
return when {
duration.isLessThanOneMinute() -> context.getString(
R.string.second_format,
duration.seconds,
)

duration.isLessThanOneHour() -> context.getString(
R.string.minute_format,
duration.toMinutes(),
)

duration.isLessThanOneDay() -> context.getString(
R.string.hour_format,
duration.toHours(),
)

duration.isLessThanSevenDays() -> context.getString(R.string.day_format, duration.toDays())
else -> format(DateTimeFormatter.ofPattern(DATE_FORMAT))
}
}

private fun Duration.isLessThanOneMinute() = toMinutes() < 1
private fun Duration.isLessThanOneHour() = toHours() < 1
private fun Duration.isLessThanOneDay() = toDays() < 1
private fun Duration.isLessThanSevenDays() = toDays() < 7

private const val DATE_FORMAT = "MM월 DD일"
5 changes: 5 additions & 0 deletions core/ui/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,9 @@
<string name="life">"생활"</string>
<string name="hobby">"취미"</string>
<string name="economy">"경제"</string>
<string name="second_format">%1$d초 전</string>
<string name="minute_format">%1$d분 전</string>
<string name="hour_format">%1$d시간 전</string>
<string name="day_format">%1$d일 전</string>

</resources>
5 changes: 4 additions & 1 deletion feature/postlist/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,7 @@ android {
namespace = "com.withpeace.withpeace.feature.postlist"
}

dependencies {}
dependencies {
implementation(libs.skydoves.landscapist.bom)
implementation(libs.skydoves.landscapist.glide)
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,37 @@
package com.withpeace.withpeace.feature.postlist

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
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.layout.wrapContentHeight
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.constraintlayout.compose.ConstraintLayout
import androidx.constraintlayout.compose.Dimension
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.skydoves.landscapist.glide.GlideImage
import com.withpeace.withpeace.core.designsystem.theme.PretendardFont
import com.withpeace.withpeace.core.designsystem.theme.WithpeaceTheme
import com.withpeace.withpeace.core.designsystem.ui.WithpeaceCard
import com.withpeace.withpeace.core.domain.model.post.Post
import com.withpeace.withpeace.core.domain.model.post.PostTopic
import com.withpeace.withpeace.core.ui.R
import com.withpeace.withpeace.core.ui.toRelativeString
import java.time.LocalDateTime

@Composable
Expand All @@ -35,13 +54,81 @@ fun PostListScreen(
postList: List<Post>,
onTopicChanged: (PostTopic) -> Unit = {},
) {
val context = LocalContext.current
Column(modifier = Modifier.fillMaxSize()) {
Spacer(modifier = Modifier.height(8.dp))
TopicTabs(
currentTopic = currentTopic,
onClick = onTopicChanged,
tabPosition = PostTopic.findIndex(currentTopic),
)
LazyColumn(
contentPadding = PaddingValues(horizontal = 24.dp, vertical = 16.dp),
verticalArrangement = Arrangement.spacedBy(8.dp),
) {
items(
items = postList,
key = {it.postId}
) { post ->
WithpeaceCard(
modifier = Modifier.fillMaxWidth(),
) {
ConstraintLayout(
modifier = Modifier
.padding(vertical = 15.dp, horizontal = 16.dp)
.fillMaxWidth()
.wrapContentHeight(),
) {
val (column, image) = createRefs()
Column(
modifier = Modifier
.padding(end = 8.dp)
.constrainAs(column) {
top.linkTo(parent.top)
start.linkTo(parent.start)
end.linkTo(image.start)
width = Dimension.fillToConstraints
},
) {
Text(
text = post.title,
fontFamily = PretendardFont,
fontWeight = FontWeight.Bold,
fontSize = 16.sp,
overflow = TextOverflow.Ellipsis,
maxLines = 1,
)
Text(
modifier = Modifier.padding(vertical = 8.dp),
text = post.content,
style = WithpeaceTheme.typography.caption,
maxLines = 2,
overflow = TextOverflow.Ellipsis,
)
Text(
text = post.createDate.toRelativeString(context),
fontFamily = PretendardFont,
fontWeight = FontWeight.Normal,
color = WithpeaceTheme.colors.SystemGray2,
fontSize = 12.sp
)
}
GlideImage(
modifier = Modifier
.constrainAs(image) {
top.linkTo(column.top)
bottom.linkTo(column.bottom)
end.linkTo(parent.end)
height = Dimension.fillToConstraints
width = Dimension.ratio("1:1")
},
imageModel = { post.postImageUrl },
previewPlaceholder = R.drawable.ic_freedom,
)
}
}
}
}
}
}

Expand All @@ -55,7 +142,7 @@ private fun PostListScreenPreview() {
Post(
postId = 2049,
title = "periculis",
content = "pellentesque",
content = "pellentesq\nuehaha",
postTopic = PostTopic.INFORMATION,
createDate = LocalDateTime.now(),
postImageUrl = "https://duckduckgo.com/?q=verterem",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ class PostListViewModel @Inject constructor() : ViewModel() {
// API 나오기 전까지 임시로 이렇게 하겠습니다!
private fun getPost(postTopic: PostTopic) = List(10) {
Post(
postId = 1746,
postId = it.toLong(),
title = postTopic.toString(),
content = postTopic.toString(),
content = postTopic.toString()+"\n${postTopic.toString()}",
postTopic = postTopic,
createDate = LocalDateTime.of(LocalDate.of(2024, 3, 18), LocalTime.of(12, 0, 0)),
postImageUrl = "http://withpeace.s3-website.kr.object.ncloudstorage.com/userProfile/1",
Expand Down
2 changes: 2 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ androidxActivity = "1.8.2"
coreSplashscreen = "1.0.1"
hilt = "2.48"
hiltNavigationCompose = "1.1.0"
androidxConstraintlayout = "1.0.1"

lifecycleRuntimeKtx = "2.7.0"
okhttp = "4.11.0"
Expand Down Expand Up @@ -80,6 +81,7 @@ androidx-core-splashscreen = { module = "androidx.core:core-splashscreen", versi
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "androidxCore" }
androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "androidxAppCompat" }

androidx-constraintlayout = { module = "androidx.constraintlayout:constraintlayout-compose", version.ref = "androidxConstraintlayout" }
androidx-lifecycle-runtime-ktx = { module = "androidx.lifecycle:lifecycle-runtime-ktx", version.ref = "lifecycleRuntimeKtx" }
androidx-lifecycle-runtimeCompose = { group = "androidx.lifecycle", name = "lifecycle-runtime-compose", version.ref = "androidxLifecycle" }
androidx-lifecycle-viewModelCompose = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-compose", version.ref = "androidxLifecycle" }
Expand Down
Loading