Skip to content

Commit 40007b3

Browse files
authored
🔀 #51 from boostcampwm-2022/feat/recruitPost
홍보 글 작성 기능 구현, 홍보 글 불러오기 기능 구현
2 parents 69e0fb6 + 4c9d154 commit 40007b3

File tree

14 files changed

+323
-50
lines changed

14 files changed

+323
-50
lines changed

data/src/main/java/com/whyranoid/data/Post/PostDataSource.kt

Lines changed: 71 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,17 @@ package com.whyranoid.data.Post
33
import com.google.firebase.firestore.FirebaseFirestore
44
import com.whyranoid.data.constant.CollectionId
55
import com.whyranoid.data.model.GroupInfoResponse
6+
import com.whyranoid.data.model.RecruitPostResponse
67
import com.whyranoid.data.model.UserResponse
78
import com.whyranoid.data.model.toGroupInfo
89
import com.whyranoid.data.model.toUser
10+
import com.whyranoid.domain.model.Post
911
import com.whyranoid.domain.model.RecruitPost
1012
import com.whyranoid.domain.model.toRule
13+
import kotlinx.coroutines.channels.awaitClose
14+
import kotlinx.coroutines.flow.Flow
15+
import kotlinx.coroutines.flow.callbackFlow
1116
import kotlinx.coroutines.suspendCancellableCoroutine
12-
import kotlinx.coroutines.tasks.await
1317
import java.util.*
1418
import javax.inject.Inject
1519
import kotlin.coroutines.resume
@@ -18,50 +22,80 @@ class PostDataSource @Inject constructor(
1822
private val db: FirebaseFirestore
1923
) {
2024

25+
// TODO : 타입을 확인하고 캐스팅하는 부분 필요
26+
fun getAllPostFlow(): Flow<List<Post>> =
27+
callbackFlow {
28+
db.collection(CollectionId.POST_COLLECTION)
29+
.addSnapshotListener { snapshot, _ ->
30+
val recruitPostList = mutableListOf<Post>()
31+
snapshot?.forEach { docuemnt ->
32+
docuemnt.toObject(RecruitPostResponse::class.java).let { postResponse ->
33+
34+
db.collection(CollectionId.USERS_COLLECTION)
35+
.document(postResponse.authorId)
36+
.get()
37+
.addOnSuccessListener { authorDocument ->
38+
val authorResponse =
39+
authorDocument?.toObject(UserResponse::class.java)
40+
41+
authorResponse?.let {
42+
db.collection(CollectionId.GROUPS_COLLECTION)
43+
.document(postResponse.groupId)
44+
.get()
45+
.addOnSuccessListener { groupDocument ->
46+
val groupInfoResponse =
47+
groupDocument.toObject(GroupInfoResponse::class.java)
48+
49+
groupInfoResponse?.let { groupInfoResponse ->
50+
val author = authorResponse.toUser()
51+
recruitPostList.add(
52+
RecruitPost(
53+
postId = postResponse.postId,
54+
author = author,
55+
updatedAt = postResponse.updatedAt,
56+
groupInfo = groupInfoResponse
57+
.toGroupInfo(
58+
author,
59+
rules = groupInfoResponse.rules.map {
60+
it.toRule()
61+
}
62+
)
63+
)
64+
)
65+
trySend(recruitPostList)
66+
}
67+
}
68+
}
69+
}
70+
}
71+
}
72+
}
73+
74+
awaitClose()
75+
}
76+
2177
suspend fun createRecruitPost(
2278
authorUid: String,
23-
updatedAt: Long,
2479
groupUid: String
2580
): Boolean {
2681
val postId = UUID.randomUUID().toString()
2782

28-
val author = db.collection(CollectionId.USERS_COLLECTION)
29-
.document(authorUid)
30-
.get()
31-
.await()
32-
.toObject(UserResponse::class.java)
33-
?.toUser()
34-
35-
author?.let {
36-
val groupInfo = db.collection(CollectionId.GROUPS_COLLECTION)
37-
.document(groupUid)
38-
.get()
39-
.await()
40-
.toObject(GroupInfoResponse::class.java)
83+
return suspendCancellableCoroutine { cancellableContinuation ->
4184

42-
groupInfo?.let {
43-
return suspendCancellableCoroutine { cancellableContinuation ->
44-
45-
db.collection(CollectionId.POST_COLLECTION)
46-
.document(postId)
47-
.set(
48-
RecruitPost(
49-
postId = postId,
50-
author = author,
51-
updatedAt = updatedAt,
52-
groupInfo = groupInfo.toGroupInfo(
53-
leader = author,
54-
rules = groupInfo.rules.map { it.toRule() }
55-
)
56-
)
57-
).addOnSuccessListener {
58-
cancellableContinuation.resume(true)
59-
}.addOnFailureListener {
60-
cancellableContinuation.resume(false)
61-
}
85+
db.collection(CollectionId.POST_COLLECTION)
86+
.document(postId)
87+
.set(
88+
RecruitPostResponse(
89+
postId = postId,
90+
authorId = authorUid,
91+
updatedAt = System.currentTimeMillis(),
92+
groupId = groupUid
93+
)
94+
).addOnSuccessListener {
95+
cancellableContinuation.resume(true)
96+
}.addOnFailureListener {
97+
cancellableContinuation.resume(false)
6298
}
63-
}
6499
}
65-
return false
66100
}
67101
}

data/src/main/java/com/whyranoid/data/Post/PostRepositoryImpl.kt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ class PostRepositoryImpl @Inject constructor(
1616
TODO("Not yet implemented")
1717
}
1818

19+
override fun getAllPostFlow(): Flow<List<Post>> {
20+
return postDataSource.getAllPostFlow()
21+
}
22+
1923
override suspend fun createPost(
2024
user: User,
2125
postContent: String,
@@ -27,10 +31,9 @@ class PostRepositoryImpl @Inject constructor(
2731

2832
override suspend fun createRecruitPost(
2933
authorUid: String,
30-
updatedAt: Long,
3134
groupUid: String
3235
): Boolean {
33-
return postDataSource.createRecruitPost(authorUid, updatedAt, groupUid)
36+
return postDataSource.createRecruitPost(authorUid, groupUid)
3437
}
3538

3639
override suspend fun deletePost(postId: String): Boolean {

data/src/main/java/com/whyranoid/data/model/PostResponse.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@ package com.whyranoid.data.model
22

33
sealed interface PostResponse {
44
val postId: String
5-
val author: String
5+
val authorId: String
66
val updatedAt: Long
77
}
88

99
data class RecruitPostResponse(
10+
override val authorId: String = "",
11+
val groupId: String = "",
1012
override val postId: String = "",
11-
override val author: String = "",
12-
override val updatedAt: Long = 0L,
13-
val groupUid: String = ""
13+
override val updatedAt: Long = 0L
1414
) : PostResponse

domain/src/main/java/com/whyranoid/domain/repository/PostRepository.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ interface PostRepository {
1111
// 글(홍보 / 인증) 페이징으로 가져오기 - 리모트
1212
fun getPagingPosts(): Flow<List<Post>>
1313

14+
fun getAllPostFlow(): Flow<List<Post>>
15+
1416
// 글 작성하기 - 리모트
1517
suspend fun createPost(
1618
user: User,
@@ -21,7 +23,6 @@ interface PostRepository {
2123

2224
suspend fun createRecruitPost(
2325
authorUid: String,
24-
updatedAt: Long,
2526
groupUid: String
2627
): Boolean
2728

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.whyranoid.domain.usecase
2+
3+
import com.whyranoid.domain.repository.AccountRepository
4+
import com.whyranoid.domain.repository.PostRepository
5+
import javax.inject.Inject
6+
7+
class CreateRecruitPostUseCase @Inject constructor(
8+
private val postRepository: PostRepository,
9+
private val accountRepository: AccountRepository
10+
) {
11+
// TODO : accountRepository에서 User를 가져오도록 수정
12+
suspend operator fun invoke(
13+
authorUid: String,
14+
groupUid: String
15+
): Boolean {
16+
return postRepository.createRecruitPost(authorUid, groupUid)
17+
}
18+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.whyranoid.domain.usecase
2+
3+
import com.whyranoid.domain.model.Post
4+
import com.whyranoid.domain.repository.PostRepository
5+
import kotlinx.coroutines.flow.Flow
6+
import javax.inject.Inject
7+
8+
class GetPostsUseCase @Inject constructor(
9+
private val postRepository: PostRepository
10+
) {
11+
12+
operator fun invoke(): Flow<List<Post>> {
13+
return postRepository.getAllPostFlow()
14+
}
15+
}

presentation/src/main/java/com/whyranoid/presentation/community/CommunityItemFragment.kt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ internal class CommunityItemFragment :
4040
when (category) {
4141
CommunityCategory.BOARD -> {
4242
// TODO: Adapter 설정
43+
setPostAdapter()
4344
}
4445
CommunityCategory.MY_GROUP -> {
4546
setMyGroupAdapter()
@@ -68,6 +69,19 @@ internal class CommunityItemFragment :
6869
}
6970
}
7071

72+
private fun setPostAdapter() {
73+
// TODO uid를 데이터 소스에서 가져오도록 수정
74+
val postAdapter = PostAdapter("hsjeon")
75+
binding.rvCommunity.adapter = postAdapter
76+
77+
viewLifecycleOwner.repeatWhenUiStarted {
78+
viewModel.postList.collect { postList ->
79+
removeShimmer()
80+
postAdapter.submitList(postList)
81+
}
82+
}
83+
}
84+
7185
// TODO 카테고리 별 다른 아이템 처리
7286
private fun setMyGroupAdapter() {
7387
val myGroupAdapter = MyGroupAdapter { groupInfo ->

presentation/src/main/java/com/whyranoid/presentation/community/CommunityViewModel.kt

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ package com.whyranoid.presentation.community
22

33
import androidx.lifecycle.ViewModel
44
import androidx.lifecycle.viewModelScope
5+
import com.whyranoid.domain.model.Post
56
import com.whyranoid.domain.usecase.GetMyGroupListUseCase
7+
import com.whyranoid.domain.usecase.GetPostsUseCase
68
import com.whyranoid.presentation.model.GroupInfoUiModel
79
import com.whyranoid.presentation.model.toGroupInfoUiModel
810
import dagger.hilt.android.lifecycle.HiltViewModel
@@ -19,9 +21,14 @@ import javax.inject.Inject
1921

2022
@HiltViewModel
2123
class CommunityViewModel @Inject constructor(
22-
getMyGroupListUseCase: GetMyGroupListUseCase
24+
getMyGroupListUseCase: GetMyGroupListUseCase,
25+
getPostsUseCase: GetPostsUseCase
2326
) : ViewModel() {
2427

28+
private val _postList = MutableStateFlow<List<Post>>(emptyList())
29+
val postList: StateFlow<List<Post>>
30+
get() = _postList.asStateFlow()
31+
2532
private val _myGroupList = MutableStateFlow<List<GroupInfoUiModel>>(emptyList())
2633
val myGroupList: StateFlow<List<GroupInfoUiModel>>
2734
get() = _myGroupList.asStateFlow()
@@ -46,5 +53,9 @@ class CommunityViewModel @Inject constructor(
4653
groupInfo.toGroupInfoUiModel()
4754
}
4855
}.launchIn(viewModelScope)
56+
57+
getPostsUseCase().onEach { postList ->
58+
_postList.value = postList
59+
}.launchIn(viewModelScope)
4960
}
5061
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package com.whyranoid.presentation.community
2+
3+
import android.view.LayoutInflater
4+
import android.view.View
5+
import android.view.ViewGroup
6+
import androidx.recyclerview.widget.DiffUtil
7+
import androidx.recyclerview.widget.ListAdapter
8+
import androidx.recyclerview.widget.RecyclerView
9+
import com.whyranoid.domain.model.Post
10+
import com.whyranoid.domain.model.RecruitPost
11+
import com.whyranoid.presentation.databinding.ItemRecruitPostBinding
12+
13+
class PostAdapter(private val myUid: String) :
14+
ListAdapter<Post, PostAdapter.RecruitPostViewHolder>(diffUtil) {
15+
16+
companion object {
17+
val diffUtil = object : DiffUtil.ItemCallback<Post>() {
18+
override fun areItemsTheSame(oldItem: Post, newItem: Post) =
19+
oldItem.postId == newItem.postId
20+
21+
override fun areContentsTheSame(oldItem: Post, newItem: Post) =
22+
oldItem == newItem
23+
}
24+
}
25+
26+
inner class RecruitPostViewHolder(
27+
parent: ViewGroup,
28+
private val binding: ItemRecruitPostBinding = ItemRecruitPostBinding.inflate(
29+
LayoutInflater.from(parent.context),
30+
parent,
31+
false
32+
)
33+
) : RecyclerView.ViewHolder(binding.root) {
34+
fun bind(post: Post) {
35+
if (post is RecruitPost) {
36+
binding.recruitPost = post
37+
if (myUid == post.author.uid) {
38+
println("테스트 $myUid ${post.author.uid}")
39+
binding.btnJoinGroup.visibility = View.GONE
40+
} else {
41+
binding.btnJoinGroup.visibility = View.VISIBLE
42+
}
43+
}
44+
}
45+
}
46+
47+
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecruitPostViewHolder {
48+
return RecruitPostViewHolder(parent)
49+
}
50+
51+
override fun onBindViewHolder(holder: RecruitPostViewHolder, position: Int) {
52+
holder.bind(getItem(position))
53+
}
54+
}

presentation/src/main/java/com/whyranoid/presentation/community/group/detail/Event.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@ package com.whyranoid.presentation.community.group.detail
33
sealed class Event {
44
object RecruitButtonClick : Event()
55
object ExitGroupButtonClick : Event()
6+
data class RecruitSnackBarButtonClick(val isSuccess: Boolean = true) : Event()
67
}

0 commit comments

Comments
 (0)