Skip to content

Commit 3d0a5d6

Browse files
committed
✨ 게시글을 페이징으로 불러오도록 변경
1 parent 23d602c commit 3d0a5d6

File tree

12 files changed

+353
-49
lines changed

12 files changed

+353
-49
lines changed
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
package com.whyranoid.data.post
2+
3+
import androidx.paging.PagingSource
4+
import androidx.paging.PagingState
5+
import com.google.firebase.firestore.FirebaseFirestore
6+
import com.google.firebase.firestore.Query
7+
import com.google.firebase.firestore.QuerySnapshot
8+
import com.whyranoid.data.constant.CollectionId
9+
import com.whyranoid.data.constant.FieldId
10+
import com.whyranoid.data.constant.FieldId.UPDATED_AT
11+
import com.whyranoid.data.model.GroupInfoResponse
12+
import com.whyranoid.data.model.RecruitPostResponse
13+
import com.whyranoid.data.model.RunningPostResponse
14+
import com.whyranoid.data.model.UserResponse
15+
import com.whyranoid.data.model.toGroupInfo
16+
import com.whyranoid.data.model.toUser
17+
import com.whyranoid.domain.model.Post
18+
import com.whyranoid.domain.model.RecruitPost
19+
import com.whyranoid.domain.model.RunningHistory
20+
import com.whyranoid.domain.model.RunningPost
21+
import com.whyranoid.domain.model.toRule
22+
import kotlinx.coroutines.tasks.await
23+
import javax.inject.Inject
24+
import javax.inject.Singleton
25+
26+
@Singleton
27+
class MyPostPagingDataSource @Inject constructor(
28+
private val db: FirebaseFirestore
29+
) : PagingSource<QuerySnapshot, Post>() {
30+
31+
private lateinit var myUid: String
32+
33+
override fun getRefreshKey(state: PagingState<QuerySnapshot, Post>): QuerySnapshot? {
34+
TODO("Not yet implemented")
35+
}
36+
37+
override suspend fun load(params: LoadParams<QuerySnapshot>): LoadResult<QuerySnapshot, Post> {
38+
return try {
39+
val postList = mutableListOf<Post>()
40+
// 현재 페이지
41+
val currentPage = params.key ?: db.collection(CollectionId.POST_COLLECTION)
42+
.orderBy(UPDATED_AT, Query.Direction.DESCENDING)
43+
.limit(10)
44+
.get()
45+
.await()
46+
47+
// Post 타입 캐스팅
48+
// TODO 예외 처리
49+
currentPage.forEach { document ->
50+
51+
if (document[FieldId.RUNNING_HISTORY_ID] != null) {
52+
document.toObject(RunningPostResponse::class.java).let { postResponse ->
53+
val authorResponse = db.collection(CollectionId.USERS_COLLECTION)
54+
.document(postResponse.authorId)
55+
.get()
56+
.await()
57+
.toObject(UserResponse::class.java)
58+
59+
authorResponse?.let {
60+
val runningHistory =
61+
db.collection(CollectionId.RUNNING_HISTORY_COLLECTION)
62+
.document(postResponse.runningHistoryId)
63+
.get()
64+
.await()
65+
.toObject(RunningHistory::class.java)
66+
67+
runningHistory?.let {
68+
postList.add(
69+
RunningPost(
70+
postId = postResponse.postId,
71+
author = authorResponse.toUser(),
72+
updatedAt = postResponse.updatedAt,
73+
runningHistory = it,
74+
likeCount = 0,
75+
content = postResponse.content
76+
)
77+
)
78+
}
79+
}
80+
}
81+
} else {
82+
document.toObject(RecruitPostResponse::class.java).let { postResponse ->
83+
val authorResponse = db.collection(CollectionId.USERS_COLLECTION)
84+
.document(postResponse.authorId)
85+
.get()
86+
.await()
87+
.toObject(UserResponse::class.java)
88+
89+
authorResponse?.let {
90+
val groupInfoResponse = db.collection(CollectionId.GROUPS_COLLECTION)
91+
.document(postResponse.groupId)
92+
.get()
93+
.await()
94+
.toObject(GroupInfoResponse::class.java)
95+
96+
groupInfoResponse?.let {
97+
val author = authorResponse.toUser()
98+
postList.add(
99+
RecruitPost(
100+
postId = postResponse.postId,
101+
author = author,
102+
updatedAt = postResponse.updatedAt,
103+
groupInfo = groupInfoResponse
104+
.toGroupInfo(
105+
author,
106+
rules = groupInfoResponse.rules.map {
107+
it.toRule()
108+
}
109+
)
110+
)
111+
)
112+
}
113+
}
114+
}
115+
}
116+
}
117+
118+
// 마지막 스냅샷 저장
119+
val lastDocumentSnapshot = currentPage.documents[currentPage.size() - 1]
120+
121+
// 마지막 스냅샷 이후 페이지 불러오기
122+
val nextPage = db.collection(CollectionId.POST_COLLECTION)
123+
.orderBy(UPDATED_AT, Query.Direction.DESCENDING)
124+
.limit(10).startAfter(lastDocumentSnapshot)
125+
.get()
126+
.await()
127+
128+
LoadResult.Page(
129+
data = postList,
130+
prevKey = null,
131+
nextKey = nextPage
132+
)
133+
} catch (e: Exception) {
134+
LoadResult.Error(e)
135+
}
136+
}
137+
138+
fun setMyUid(myUid: String) {
139+
this.myUid = myUid
140+
}
141+
}

data/src/main/java/com/whyranoid/data/post/PostDataSourceImpl.kt

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ class PostDataSourceImpl @Inject constructor(
3131
private val db: FirebaseFirestore
3232
) : PostDataSource {
3333

34-
// TODO : 조금 더 간결하게 처리 필요.
34+
// TODO : 조금 더 간결하게 처리 필요.
35+
// TODO : 페이징 처리가 잘 끝나면 삭제
3536
override fun getAllPostFlow(): Flow<List<Post>> =
3637
callbackFlow {
3738
db.collection(CollectionId.POST_COLLECTION)
@@ -124,17 +125,18 @@ class PostDataSourceImpl @Inject constructor(
124125
awaitClose()
125126
}
126127

128+
// TODO : 페이징 처리가 잘 끝나면 삭제
127129
override fun getMyPostFlow(uid: String): Flow<List<Post>> =
128130
callbackFlow {
129131
db.collection(CollectionId.POST_COLLECTION)
130132
.whereEqualTo(AUTHOR_ID, uid)
131133
.orderBy(UPDATED_AT, Query.Direction.DESCENDING)
132134
.addSnapshotListener { snapshot, _ ->
133135
val postList = mutableListOf<Post>()
134-
snapshot?.forEach { docuemnt ->
136+
snapshot?.forEach { document ->
135137

136-
if (docuemnt[RUNNING_HISTORY_ID] != null) {
137-
docuemnt.toObject(RunningPostResponse::class.java).let { postResponse ->
138+
if (document[RUNNING_HISTORY_ID] != null) {
139+
document.toObject(RunningPostResponse::class.java).let { postResponse ->
138140
db.collection(CollectionId.USERS_COLLECTION)
139141
.document(postResponse.authorId)
140142
.get()
@@ -171,7 +173,7 @@ class PostDataSourceImpl @Inject constructor(
171173
}
172174
}
173175
} else {
174-
docuemnt.toObject(RecruitPostResponse::class.java).let { postResponse ->
176+
document.toObject(RecruitPostResponse::class.java).let { postResponse ->
175177

176178
db.collection(CollectionId.USERS_COLLECTION)
177179
.document(postResponse.authorId)
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
package com.whyranoid.data.post
2+
3+
import androidx.paging.PagingSource
4+
import androidx.paging.PagingState
5+
import com.google.firebase.firestore.FirebaseFirestore
6+
import com.google.firebase.firestore.Query
7+
import com.google.firebase.firestore.QuerySnapshot
8+
import com.whyranoid.data.constant.CollectionId
9+
import com.whyranoid.data.constant.CollectionId.POST_COLLECTION
10+
import com.whyranoid.data.constant.FieldId.RUNNING_HISTORY_ID
11+
import com.whyranoid.data.constant.FieldId.UPDATED_AT
12+
import com.whyranoid.data.model.GroupInfoResponse
13+
import com.whyranoid.data.model.RecruitPostResponse
14+
import com.whyranoid.data.model.RunningPostResponse
15+
import com.whyranoid.data.model.UserResponse
16+
import com.whyranoid.data.model.toGroupInfo
17+
import com.whyranoid.data.model.toUser
18+
import com.whyranoid.domain.model.Post
19+
import com.whyranoid.domain.model.RecruitPost
20+
import com.whyranoid.domain.model.RunningHistory
21+
import com.whyranoid.domain.model.RunningPost
22+
import com.whyranoid.domain.model.toRule
23+
import kotlinx.coroutines.tasks.await
24+
import javax.inject.Inject
25+
import javax.inject.Singleton
26+
27+
@Singleton
28+
class PostPagingDataSource @Inject constructor(
29+
private val db: FirebaseFirestore
30+
) : PagingSource<QuerySnapshot, Post>() {
31+
32+
override fun getRefreshKey(state: PagingState<QuerySnapshot, Post>): QuerySnapshot? {
33+
TODO("Not yet implemented")
34+
}
35+
36+
override suspend fun load(params: LoadParams<QuerySnapshot>): LoadResult<QuerySnapshot, Post> {
37+
return try {
38+
val postList = mutableListOf<Post>()
39+
// 현재 페이지
40+
val currentPage = params.key ?: db.collection(POST_COLLECTION)
41+
.orderBy(UPDATED_AT, Query.Direction.DESCENDING)
42+
.limit(10)
43+
.get()
44+
.await()
45+
46+
// Post 타입 캐스팅
47+
// TODO 예외 처리
48+
currentPage.forEach { document ->
49+
50+
if (document[RUNNING_HISTORY_ID] != null) {
51+
document.toObject(RunningPostResponse::class.java).let { postResponse ->
52+
val authorResponse = db.collection(CollectionId.USERS_COLLECTION)
53+
.document(postResponse.authorId)
54+
.get()
55+
.await()
56+
.toObject(UserResponse::class.java)
57+
58+
authorResponse?.let {
59+
val runningHistory =
60+
db.collection(CollectionId.RUNNING_HISTORY_COLLECTION)
61+
.document(postResponse.runningHistoryId)
62+
.get()
63+
.await()
64+
.toObject(RunningHistory::class.java)
65+
66+
runningHistory?.let {
67+
postList.add(
68+
RunningPost(
69+
postId = postResponse.postId,
70+
author = authorResponse.toUser(),
71+
updatedAt = postResponse.updatedAt,
72+
runningHistory = it,
73+
likeCount = 0,
74+
content = postResponse.content
75+
)
76+
)
77+
}
78+
}
79+
}
80+
} else {
81+
document.toObject(RecruitPostResponse::class.java).let { postResponse ->
82+
val authorResponse = db.collection(CollectionId.USERS_COLLECTION)
83+
.document(postResponse.authorId)
84+
.get()
85+
.await()
86+
.toObject(UserResponse::class.java)
87+
88+
authorResponse?.let {
89+
val groupInfoResponse = db.collection(CollectionId.GROUPS_COLLECTION)
90+
.document(postResponse.groupId)
91+
.get()
92+
.await()
93+
.toObject(GroupInfoResponse::class.java)
94+
95+
groupInfoResponse?.let {
96+
val author = authorResponse.toUser()
97+
postList.add(
98+
RecruitPost(
99+
postId = postResponse.postId,
100+
author = author,
101+
updatedAt = postResponse.updatedAt,
102+
groupInfo = groupInfoResponse
103+
.toGroupInfo(
104+
author,
105+
rules = groupInfoResponse.rules.map {
106+
it.toRule()
107+
}
108+
)
109+
)
110+
)
111+
}
112+
}
113+
}
114+
}
115+
}
116+
117+
// 마지막 스냅샷 저장
118+
val lastDocumentSnapshot = currentPage.documents[currentPage.size() - 1]
119+
120+
// 마지막 스냅샷 이후 페이지 불러오기
121+
val nextPage = db.collection(POST_COLLECTION)
122+
.orderBy(UPDATED_AT, Query.Direction.DESCENDING)
123+
.limit(10).startAfter(lastDocumentSnapshot)
124+
.get()
125+
.await()
126+
127+
LoadResult.Page(
128+
data = postList,
129+
prevKey = null,
130+
nextKey = nextPage
131+
)
132+
} catch (e: Exception) {
133+
LoadResult.Error(e)
134+
}
135+
}
136+
}

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

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,35 @@
11
package com.whyranoid.data.post
22

3+
import androidx.paging.Pager
4+
import androidx.paging.PagingConfig
5+
import androidx.paging.PagingData
36
import com.whyranoid.domain.model.Post
47
import com.whyranoid.domain.repository.PostRepository
58
import kotlinx.coroutines.flow.Flow
69
import javax.inject.Inject
710

811
class PostRepositoryImpl @Inject constructor(
9-
private val postDataSource: PostDataSource
12+
private val postDataSource: PostDataSource,
13+
private val postPagingDataSource: PostPagingDataSource,
14+
private val myPostPagingDataSource: MyPostPagingDataSource
1015
) : PostRepository {
1116

12-
// TODO : 페이징처리하기
13-
override fun getPagingPosts(): Flow<List<Post>> {
14-
TODO("Not yet implemented")
17+
// TODO : 캐싱하기
18+
override fun getPagingPosts(): Flow<PagingData<Post>> {
19+
return Pager(
20+
PagingConfig(pageSize = 5)
21+
) {
22+
postPagingDataSource
23+
}.flow
24+
}
25+
26+
override fun getMyPagingPosts(uid: String): Flow<PagingData<Post>> {
27+
myPostPagingDataSource.setMyUid(uid)
28+
return Pager(
29+
PagingConfig(pageSize = 5)
30+
) {
31+
myPostPagingDataSource
32+
}.flow
1533
}
1634

1735
override fun getAllPostFlow(): Flow<List<Post>> {

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
package com.whyranoid.domain.repository
22

3+
import androidx.paging.PagingData
34
import com.whyranoid.domain.model.Post
45
import kotlinx.coroutines.flow.Flow
56

67
interface PostRepository {
78

89
// TODO : 페이징 처리
910
// 글(홍보 / 인증) 페이징으로 가져오기 - 리모트
10-
fun getPagingPosts(): Flow<List<Post>>
11+
fun getPagingPosts(): Flow<PagingData<Post>>
12+
13+
fun getMyPagingPosts(uid: String): Flow<PagingData<Post>>
1114

1215
fun getAllPostFlow(): Flow<List<Post>>
1316

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 androidx.paging.PagingData
4+
import com.whyranoid.domain.model.Post
5+
import com.whyranoid.domain.repository.AccountRepository
6+
import com.whyranoid.domain.repository.PostRepository
7+
import kotlinx.coroutines.flow.Flow
8+
import javax.inject.Inject
9+
10+
class GetMyPagingPostsUseCase @Inject constructor(
11+
private val accountRepository: AccountRepository,
12+
private val postRepository: PostRepository
13+
) {
14+
15+
suspend operator fun invoke(): Flow<PagingData<Post>> {
16+
return postRepository.getMyPagingPosts(accountRepository.getUid())
17+
}
18+
}

0 commit comments

Comments
 (0)