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/freeboarddetail #80

Merged
merged 9 commits into from
Jan 19, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 @@ -86,6 +86,14 @@ private fun PreviewProfileImage() {
ProfileImage(
profileType = ProfileType.BUTLER,
)
ProfileImage(
profileType = ProfileType.PET,
size = 180.dp,
)
ProfileImage(
profileType = ProfileType.BUTLER,
size = 180.dp,
)
}
}
}
27 changes: 1 addition & 26 deletions core/config/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,39 +1,14 @@
plugins {
alias(libs.plugins.android.library)
alias(libs.plugins.kotlin.android)
alias(libs.plugins.convention.lib.build)
}

android {
namespace = "com.lanpet.core.config"
compileSdk = 34

defaultConfig {
minSdk = 24

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles("consumer-rules.pro")
}

buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro",
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
kotlinOptions {
jvmTarget = "11"
}
}

dependencies {

implementation(libs.androidx.core.ktx)
implementation(libs.androidx.appcompat)
implementation(libs.material)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@ data class GetFreeBoardListRequestDto(
val size: Int = 10,
val category: String?,
val direction: String,
val profileId: String? = null,
) {
fun toQueryMap(): Map<String, String> =
buildMap {
cursor?.let { put("cursor", it) }
put("size", this@GetFreeBoardListRequestDto.size.toString())
if (category != null) put("category", category) else put("category", "null")
put("direction", direction)
put("profileId", profileId ?: "null")
}

companion object {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import kotlinx.coroutines.flow.timeout
import kotlinx.coroutines.runBlocking
import okhttp3.Interceptor
import okhttp3.Response
import timber.log.Timber
import javax.inject.Inject
import kotlin.time.Duration.Companion.seconds

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
package com.lanpet.domain.model

import kotlinx.serialization.Serializable

@Serializable
enum class ProfileType(
val value: String,
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ data class GetFreeBoardPostListRequest(
// When FreeBoardCategoryType is null, it means that all categories are included.
val freeBoardCategoryType: FreeBoardCategoryType?,
val direction: CursorDirection = CursorDirection.NEXT,
val profileId: String? = null,
)
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,13 @@ package com.lanpet.domain.usecase.freeboard

import com.lanpet.domain.model.free.GetFreeBoardPostListRequest
import com.lanpet.domain.repository.FreeBoardRepository
import kotlinx.coroutines.flow.map
import javax.inject.Inject

class GetFreeBoardPostListUseCase
@Inject
constructor(
private val freeBoardRepository: FreeBoardRepository,
) {
operator fun invoke(
imageBaseUrl: String = "",
getFreeBoardPostListRequest: GetFreeBoardPostListRequest,
) = freeBoardRepository.getFreeBoardPostList(getFreeBoardPostListRequest).map {
it.copy(
items =
it.items?.map {
it.copy(
resources =
it.resources?.map {
it.copy(
url = imageBaseUrl + it.url,
)
},
)
},
)
}
operator fun invoke(getFreeBoardPostListRequest: GetFreeBoardPostListRequest) =
freeBoardRepository.getFreeBoardPostList(getFreeBoardPostListRequest)
}
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,9 @@ fun FreeBoardDetailScreen(
profileId = defaultProfile.id,
)
},
onFetchComment = {
freeBoardDetailViewModel.fetchComments()
},
onLikeChange = { like ->
if (like) {
freeBoardDetailViewModel.likePost()
Expand Down Expand Up @@ -220,6 +223,7 @@ fun ContentUI(
commentInput: String,
onWriteComment: () -> Unit,
onLikeChange: (Boolean) -> Unit,
onFetchComment: () -> Unit,
modifier: Modifier = Modifier,
freeBoardLikesViewModel: FreeBoardLikesViewModel = hiltViewModel(),
) {
Expand Down Expand Up @@ -367,6 +371,10 @@ fun ContentUI(
)
FreeBoardCommentSection(
comments = state.comments,
canLoadMore = state.canLoadMoreComments,
onLoadMore = {
onFetchComment()
},
)
// line
Spacer(
Expand All @@ -387,11 +395,12 @@ fun ContentUI(
}
}

// TODO: Comment section UI
@Composable
fun FreeBoardCommentSection(
canLoadMore: Boolean,
modifier: Modifier = Modifier,
comments: List<FreeBoardComment> = emptyList(),
onLoadMore: () -> Unit = {},
) {
Column {
Text(
Expand Down Expand Up @@ -419,6 +428,21 @@ fun FreeBoardCommentSection(
comments.forEach { comment ->
FreeBoardCommentItem(freeBoardComment = comment)
}
if (canLoadMore) {
Text(
"댓글 더보기",
modifier =
Modifier
.padding(
horizontal = LanPetDimensions.Margin.medium,
vertical = LanPetDimensions.Margin.small,
).clickable(
interactionSource = null,
indication = null,
) { onLoadMore() },
style = MaterialTheme.customTypography().body2RegularSingle.copy(color = GrayColor.Gray400),
)
}
}
}
}
Expand Down Expand Up @@ -600,7 +624,11 @@ private fun FreeBoardDetailPreview() {
private fun FreeBoardCommentSection_Empty_Preview() {
BasePreviewWrapper {
Column {
FreeBoardCommentSection()
FreeBoardCommentSection(
comments = emptyList(),
canLoadMore = false,
onLoadMore = {},
)
}
}
}
Expand All @@ -609,7 +637,10 @@ private fun FreeBoardCommentSection_Empty_Preview() {
@PreviewLightDark
private fun FreeBoardCommentSection_Filled_Preview() {
BasePreviewWrapper {
FreeBoardCommentSection()
FreeBoardCommentSection(
onLoadMore = {},
canLoadMore = true,
)
}
}

Expand Down Expand Up @@ -641,6 +672,8 @@ private fun SuccessUIPreview() {
commentInput = "",
onWriteComment = {},
onLikeChange = {},
onFetchComment = {},
modifier = Modifier,
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.job
import kotlinx.coroutines.launch
import javax.inject.Inject

Expand Down Expand Up @@ -66,6 +65,7 @@ class FreeBoardDetailViewModel
FreeBoardDetailState.Success(
postDetail = detailState.postDetail,
comments = commentsState.comments,
canLoadMoreComments = commentsState.cursorPagingState.hasNext,
)
}

Expand Down Expand Up @@ -133,82 +133,86 @@ class FreeBoardDetailViewModel
}

fun refreshComments() {
viewModelScope.launch {
fetchComments()
}
commentsState.value = CommentsState.Initial
fetchComments()
}

private suspend fun fetchDetail() {
private fun fetchDetail() {
detailState.value = DetailState.Loading

getFreeBoardDetailUseCase(postId, profileId)
.catch {
detailState.value = DetailState.Error("Failed to fetch detail")
}.collect {
detailState.value = DetailState.Success(it)
}
viewModelScope.launch {
getFreeBoardDetailUseCase(postId, profileId)
.catch {
detailState.value = DetailState.Error("Failed to fetch detail")
}.collect {
detailState.value = DetailState.Success(it)
}
}
}

private suspend fun fetchComments() {
fun fetchComments() {
val pagingState =
when (commentsState.value) {
is CommentsState.Error ->
CursorPagingState(
size = 20,
size = 10,
direction = CursorDirection.NEXT,
)

CommentsState.Initial ->
CursorPagingState(
size = 20,
size = 10,
direction = CursorDirection.NEXT,
)

CommentsState.Loading ->
CursorPagingState(
size = 20,
size = 10,
direction = CursorDirection.NEXT,
)

is CommentsState.Success -> (commentsState.value as CommentsState.Success).cursorPagingState
}

getFreeBoardCommentListUseCase(
postId,
cursor = pagingState.cursor,
size = pagingState.size,
direction = pagingState.direction,
).catch {
commentsState.value = CommentsState.Error("Failed to fetch comments")
}.collect {
when (commentsState.value) {
is CommentsState.Success -> {
commentsState.value =
CommentsState.Success(
// comments = (commentsState.value as CommentsState.Success).comments + it.data,
comments = it.data,
cursorPagingState =
CursorPagingState(
hasNext = it.paginationInfo.hasNext,
cursor = it.paginationInfo.nextCursor,
size = 20,
direction = CursorDirection.NEXT,
),
)
}
if (!pagingState.hasNext) return

else ->
commentsState.value =
CommentsState.Success(
comments = it.data,
cursorPagingState =
CursorPagingState(
hasNext = it.paginationInfo.hasNext,
cursor = it.paginationInfo.nextCursor,
size = 20,
direction = CursorDirection.NEXT,
),
)
viewModelScope.launch {
getFreeBoardCommentListUseCase(
postId,
cursor = pagingState.cursor,
size = pagingState.size,
direction = pagingState.direction,
).catch {
commentsState.value = CommentsState.Error("Failed to fetch comments")
}.collect {
when (commentsState.value) {
is CommentsState.Success -> {
commentsState.value =
CommentsState.Success(
comments = (commentsState.value as CommentsState.Success).comments + it.data,
cursorPagingState =
CursorPagingState(
hasNext = it.paginationInfo.hasNext,
cursor = it.paginationInfo.nextCursor,
size = 10,
direction = CursorDirection.NEXT,
),
)
}

else ->
commentsState.value =
CommentsState.Success(
comments = it.data,
cursorPagingState =
CursorPagingState(
hasNext = it.paginationInfo.hasNext,
cursor = it.paginationInfo.nextCursor,
size = 10,
direction = CursorDirection.NEXT,
),
)
}
}
}
}
Expand Down Expand Up @@ -239,7 +243,11 @@ private sealed class CommentsState {

data class Success(
val comments: List<FreeBoardComment>,
val cursorPagingState: CursorPagingState = CursorPagingState(),
val cursorPagingState: CursorPagingState =
CursorPagingState(
size = 20,
direction = CursorDirection.NEXT,
),
val isLoadingMore: Boolean = false,
) : CommentsState()

Expand All @@ -257,6 +265,7 @@ sealed class FreeBoardDetailState {
data class Success(
val postDetail: FreeBoardPostDetail,
val comments: List<FreeBoardComment> = emptyList(),
val canLoadMoreComments: Boolean = true,
) : FreeBoardDetailState()

data class Error(
Expand Down
Loading
Loading