From c7e739c8a8cc93e6cfbc4ee597ada1e5918db42d Mon Sep 17 00:00:00 2001 From: Wooyeol Lee Date: Tue, 28 Nov 2023 17:58:21 +0900 Subject: [PATCH 1/3] feat: feat pagination in getMyCreatedEmojis, getMySavedEmojis, getMyPosts --- .../emoji/controller/EmojiController.kt | 12 +++++--- .../domain/emoji/service/EmojiService.kt | 29 ++++++++++++++----- .../domain/post/controller/PostController.kt | 8 +++-- .../springboot/domain/post/dao/PostDao.kt | 6 ++-- .../domain/post/service/PostService.kt | 7 +++-- .../emoji/controller/EmojiControllerTest.kt | 24 +++++++++++---- .../domain/emoji/service/EmojiServiceTest.kt | 9 ++++-- .../post/controller/PostControllerTest.kt | 14 ++++++--- .../springboot/domain/post/dao/PostDaoTest.kt | 4 ++- .../domain/post/service/PostServiceTest.kt | 10 ++++--- 10 files changed, 85 insertions(+), 38 deletions(-) diff --git a/springboot/src/main/kotlin/com/goliath/emojihub/springboot/domain/emoji/controller/EmojiController.kt b/springboot/src/main/kotlin/com/goliath/emojihub/springboot/domain/emoji/controller/EmojiController.kt index 331a4605..22954259 100644 --- a/springboot/src/main/kotlin/com/goliath/emojihub/springboot/domain/emoji/controller/EmojiController.kt +++ b/springboot/src/main/kotlin/com/goliath/emojihub/springboot/domain/emoji/controller/EmojiController.kt @@ -39,16 +39,20 @@ class EmojiController(private val emojiService: EmojiService) { @GetMapping("/me/created") fun getMyCreatedEmojis( - @CurrentUser username: String + @CurrentUser username: String, + @RequestParam(value = "index", defaultValue = 1.toString()) index: Int, + @RequestParam(value = "count", defaultValue = 10.toString()) count: Int, ): ResponseEntity> { - return ResponseEntity.ok(emojiService.getMyEmojis(username, CREATED_EMOJIS)) + return ResponseEntity.ok(emojiService.getMyEmojis(username, CREATED_EMOJIS, index, count)) } @GetMapping("/me/saved") fun getMySavedEmojis( - @CurrentUser username: String + @CurrentUser username: String, + @RequestParam(value = "index", defaultValue = 1.toString()) index: Int, + @RequestParam(value = "count", defaultValue = 10.toString()) count: Int, ): ResponseEntity> { - return ResponseEntity.ok(emojiService.getMyEmojis(username, SAVED_EMOJIS)) + return ResponseEntity.ok(emojiService.getMyEmojis(username, SAVED_EMOJIS, index, count)) } @GetMapping("/{id}") diff --git a/springboot/src/main/kotlin/com/goliath/emojihub/springboot/domain/emoji/service/EmojiService.kt b/springboot/src/main/kotlin/com/goliath/emojihub/springboot/domain/emoji/service/EmojiService.kt index 3faa9e7a..cca480ee 100644 --- a/springboot/src/main/kotlin/com/goliath/emojihub/springboot/domain/emoji/service/EmojiService.kt +++ b/springboot/src/main/kotlin/com/goliath/emojihub/springboot/domain/emoji/service/EmojiService.kt @@ -11,6 +11,7 @@ import com.goliath.emojihub.springboot.global.exception.CustomHttp403 import com.goliath.emojihub.springboot.global.util.getDateTimeNow import org.springframework.stereotype.Service import org.springframework.web.multipart.MultipartFile +import java.lang.Integer.min @Service class EmojiService( @@ -34,24 +35,32 @@ class EmojiService( return emojiDao.getEmojis(sortByDate, index, count) } - fun getMyEmojis(username: String, field: String): List { + fun getMyEmojis(username: String, field: String, index: Int, count: Int): List { + // index는 양의 정수여야 함 + if (index <= 0) throw CustomHttp400("Index should be positive integer.") + // count는 0보다 커야 함 + if (count <= 0) throw CustomHttp400("Count should be positive integer.") val user = userDao.getUser(username) ?: throw CustomHttp404("User doesn't exist.") val emojiIdList = if (field == CREATED_EMOJIS) { user.created_emojis } else { user.saved_emojis } - val emojiList = mutableListOf() + var emojiList = mutableListOf() if (emojiIdList != null && emojiIdList.size != 0) { for (emojiId in emojiIdList) { - val emoji = emojiDao.getEmoji(emojiId) - if (emoji != null) { - emojiList.add(emoji) - } + val emoji = emojiDao.getEmoji(emojiId) ?: continue + emojiList.add(emoji) } + // sort if (emojiList.size != 0) { emojiList.sortByDescending { it.created_at } } + // pagination + emojiList = emojiList.subList( + min((index - 1) * count, emojiList.size - 1), + min(index * count, emojiList.size) + ) } return emojiList } @@ -61,7 +70,13 @@ class EmojiService( return emojiDao.getEmoji(emojiId) } - fun postEmoji(username: String, file: MultipartFile, thumbnail: MultipartFile, emojiUnicode: String, emojiLabel: String) { + fun postEmoji( + username: String, + file: MultipartFile, + thumbnail: MultipartFile, + emojiUnicode: String, + emojiLabel: String + ) { val dateTime = getDateTimeNow() val emoji = emojiDao.insertEmoji(username, file, thumbnail, emojiUnicode, emojiLabel, dateTime) userDao.insertId(username, emoji.id, CREATED_EMOJIS) diff --git a/springboot/src/main/kotlin/com/goliath/emojihub/springboot/domain/post/controller/PostController.kt b/springboot/src/main/kotlin/com/goliath/emojihub/springboot/domain/post/controller/PostController.kt index 700649f6..a2f35671 100644 --- a/springboot/src/main/kotlin/com/goliath/emojihub/springboot/domain/post/controller/PostController.kt +++ b/springboot/src/main/kotlin/com/goliath/emojihub/springboot/domain/post/controller/PostController.kt @@ -32,9 +32,11 @@ class PostController(private val postService: PostService) { @GetMapping("/me") fun getMyPosts( - @CurrentUser username: String - ): ResponseEntity>{ - return ResponseEntity.ok(postService.getMyPosts(username)) + @CurrentUser username: String, + @RequestParam(value = "index", defaultValue = 1.toString()) index: Int, + @RequestParam(value = "count", defaultValue = 10.toString()) count: Int + ): ResponseEntity> { + return ResponseEntity.ok(postService.getMyPosts(username, index, count)) } @GetMapping("/{id}") diff --git a/springboot/src/main/kotlin/com/goliath/emojihub/springboot/domain/post/dao/PostDao.kt b/springboot/src/main/kotlin/com/goliath/emojihub/springboot/domain/post/dao/PostDao.kt index 4dbef52f..e83fb19f 100644 --- a/springboot/src/main/kotlin/com/goliath/emojihub/springboot/domain/post/dao/PostDao.kt +++ b/springboot/src/main/kotlin/com/goliath/emojihub/springboot/domain/post/dao/PostDao.kt @@ -40,12 +40,12 @@ class PostDao( return list } - fun getMyPosts(username: String): List { + fun getMyPosts(username: String, index: Int, count: Int): List { val list = mutableListOf() val postsRef = db.collection(POST_COLLECTION_NAME) val postQuery = postsRef.whereEqualTo("created_by", username) - .orderBy("created_at", Query.Direction.DESCENDING) - val documents = postQuery.get().get().documents + .orderBy(CREATED_AT, Query.Direction.DESCENDING) + val documents: List = postQuery.offset((index - 1) * count).limit(count).get().get().documents for (document in documents) { list.add(document.toObject(PostDto::class.java)) } diff --git a/springboot/src/main/kotlin/com/goliath/emojihub/springboot/domain/post/service/PostService.kt b/springboot/src/main/kotlin/com/goliath/emojihub/springboot/domain/post/service/PostService.kt index 763a403a..a716e4fc 100644 --- a/springboot/src/main/kotlin/com/goliath/emojihub/springboot/domain/post/service/PostService.kt +++ b/springboot/src/main/kotlin/com/goliath/emojihub/springboot/domain/post/service/PostService.kt @@ -27,14 +27,15 @@ class PostService( fun getPosts(index: Int, count: Int): List { if (index <= 0) throw CustomHttp400("Index should be positive integer.") - // count는 0보다 커야 함 if (count <= 0) throw CustomHttp400("Count should be positive integer.") return postDao.getPosts(index, count) } - fun getMyPosts(username: String): List { + fun getMyPosts(username: String, index: Int, count: Int): List { + if (index <= 0) throw CustomHttp400("Index should be positive integer.") + if (count <= 0) throw CustomHttp400("Count should be positive integer.") if (!userDao.existUser(username)) throw CustomHttp404("User doesn't exist.") - return postDao.getMyPosts(username) + return postDao.getMyPosts(username, index, count) } fun getPost(postId: String): PostDto? { diff --git a/springboot/src/test/kotlin/com/goliath/emojihub/springboot/domain/emoji/controller/EmojiControllerTest.kt b/springboot/src/test/kotlin/com/goliath/emojihub/springboot/domain/emoji/controller/EmojiControllerTest.kt index 7a0f5bc0..a4426f31 100644 --- a/springboot/src/test/kotlin/com/goliath/emojihub/springboot/domain/emoji/controller/EmojiControllerTest.kt +++ b/springboot/src/test/kotlin/com/goliath/emojihub/springboot/domain/emoji/controller/EmojiControllerTest.kt @@ -81,10 +81,16 @@ internal class EmojiControllerTest @Autowired constructor( fun getMyCreatedEmojis() { // given val username = "custom_username" - Mockito.`when`(emojiService.getMyEmojis(username, CREATED_EMOJIS)).thenReturn(emojiList) + val index = 1 + val count = testDto.createdEmojiSize + Mockito.`when`(emojiService.getMyEmojis(username, CREATED_EMOJIS, index, count)).thenReturn(emojiList) // when - val result = this.mockMvc.perform(get("/api/emoji/me/created")) + val result = this.mockMvc.perform( + get("/api/emoji/me/created") + .param("index", index.toString()) + .param("count", count.toString()) + ) // then result.andExpect(status().isOk) @@ -97,7 +103,7 @@ internal class EmojiControllerTest @Autowired constructor( .andExpect(jsonPath("$[0].emoji_label").value(emojiList[0].emoji_label)) .andExpect(jsonPath("$[0].created_at").value(emojiList[0].created_at)) .andExpect(jsonPath("$[0].num_saved").value(emojiList[0].num_saved)) - verify(emojiService, times(1)).getMyEmojis(username, CREATED_EMOJIS) + verify(emojiService, times(1)).getMyEmojis(username, CREATED_EMOJIS, index, count) } @Test @@ -106,10 +112,16 @@ internal class EmojiControllerTest @Autowired constructor( fun getMySavedEmojis() { // given val username = "custom_username" - Mockito.`when`(emojiService.getMyEmojis(username, SAVED_EMOJIS)).thenReturn(emojiList) + val index = 1 + val count = testDto.savedEmojiSize + Mockito.`when`(emojiService.getMyEmojis(username, SAVED_EMOJIS, index, count)).thenReturn(emojiList) // when - val result = this.mockMvc.perform(get("/api/emoji/me/saved")) + val result = this.mockMvc.perform( + get("/api/emoji/me/saved") + .param("index", index.toString()) + .param("count", count.toString()) + ) // then result.andExpect(status().isOk) @@ -122,7 +134,7 @@ internal class EmojiControllerTest @Autowired constructor( .andExpect(jsonPath("$[0].emoji_label").value(emojiList[0].emoji_label)) .andExpect(jsonPath("$[0].created_at").value(emojiList[0].created_at)) .andExpect(jsonPath("$[0].num_saved").value(emojiList[0].num_saved)) - verify(emojiService, times(1)).getMyEmojis(username, SAVED_EMOJIS) + verify(emojiService, times(1)).getMyEmojis(username, SAVED_EMOJIS, index, count) } @Test diff --git a/springboot/src/test/kotlin/com/goliath/emojihub/springboot/domain/emoji/service/EmojiServiceTest.kt b/springboot/src/test/kotlin/com/goliath/emojihub/springboot/domain/emoji/service/EmojiServiceTest.kt index 86cd62e3..f806962c 100644 --- a/springboot/src/test/kotlin/com/goliath/emojihub/springboot/domain/emoji/service/EmojiServiceTest.kt +++ b/springboot/src/test/kotlin/com/goliath/emojihub/springboot/domain/emoji/service/EmojiServiceTest.kt @@ -86,6 +86,9 @@ internal class EmojiServiceTest { val user = testDto.userList[0] val username = user.username val wrongUsername = "wrong_username" + val index = 1 + val countCreated = testDto.createdEmojiSize + val countSaved = testDto.savedEmojiSize Mockito.`when`(userDao.getUser(username)).thenReturn(user) Mockito.`when`(userDao.getUser(wrongUsername)).thenReturn(null) for (emoji in testDto.emojiList) { @@ -93,10 +96,10 @@ internal class EmojiServiceTest { } // when - val createdEmojisResult = emojiService.getMyEmojis(username, CREATED_EMOJIS) - val savedEmojisResult = emojiService.getMyEmojis(username, SAVED_EMOJIS) + val createdEmojisResult = emojiService.getMyEmojis(username, CREATED_EMOJIS, index, countCreated) + val savedEmojisResult = emojiService.getMyEmojis(username, SAVED_EMOJIS, index, countSaved) val assertThrows = assertThrows(CustomHttp404::class.java) { - emojiService.getMyEmojis(wrongUsername, CREATED_EMOJIS) + emojiService.getMyEmojis(wrongUsername, CREATED_EMOJIS, index, countCreated) } // then diff --git a/springboot/src/test/kotlin/com/goliath/emojihub/springboot/domain/post/controller/PostControllerTest.kt b/springboot/src/test/kotlin/com/goliath/emojihub/springboot/domain/post/controller/PostControllerTest.kt index ce1e2766..977426e2 100644 --- a/springboot/src/test/kotlin/com/goliath/emojihub/springboot/domain/post/controller/PostControllerTest.kt +++ b/springboot/src/test/kotlin/com/goliath/emojihub/springboot/domain/post/controller/PostControllerTest.kt @@ -27,7 +27,7 @@ import org.springframework.test.web.servlet.result.MockMvcResultMatchers.* @WebMvcTest(PostController::class) internal class PostControllerTest @Autowired constructor( private val mockMvc: MockMvc -){ +) { @Autowired private lateinit var objectMapper: ObjectMapper @@ -103,16 +103,22 @@ internal class PostControllerTest @Autowired constructor( // given val username = "custom_username" val realUsername = postList[0].created_by + val index = 1 + val count = testDto.postSize val posts = mutableListOf() for (post in postList) { if (post.created_by == realUsername) { posts.add(post) } } - given(postService.getMyPosts(username)).willReturn(posts) + given(postService.getMyPosts(username, index, count)).willReturn(posts) // when - val result = this.mockMvc.perform(get("/api/post/me")) + val result = this.mockMvc.perform( + get("/api/post/me") + .param("index", index.toString()) + .param("count", count.toString()) + ) // then result.andExpect(status().isOk) @@ -123,7 +129,7 @@ internal class PostControllerTest @Autowired constructor( .andExpect(jsonPath("$[0].content").value(posts[0].content)) .andExpect(jsonPath("$[0].created_at").value(posts[0].created_at)) .andExpect(jsonPath("$[0].modified_at").value(posts[0].modified_at)) - verify(postService, times(1)).getMyPosts(username) + verify(postService, times(1)).getMyPosts(username, index, count) } @Test diff --git a/springboot/src/test/kotlin/com/goliath/emojihub/springboot/domain/post/dao/PostDaoTest.kt b/springboot/src/test/kotlin/com/goliath/emojihub/springboot/domain/post/dao/PostDaoTest.kt index dcefaae4..1f5d3e76 100644 --- a/springboot/src/test/kotlin/com/goliath/emojihub/springboot/domain/post/dao/PostDaoTest.kt +++ b/springboot/src/test/kotlin/com/goliath/emojihub/springboot/domain/post/dao/PostDaoTest.kt @@ -107,6 +107,8 @@ internal class PostDaoTest { fun getMyPosts() { // given val username = userList[0].username + val index = 1 + val count = testDto.postSize val postListForUser = mutableListOf() postListForUser.add(postList[1]) postListForUser.add(postList[0]) @@ -114,7 +116,7 @@ internal class PostDaoTest { .thenReturn(testDB.collection(POST_COLLECTION_NAME)) // when - val result = postDao.getMyPosts(username) + val result = postDao.getMyPosts(username, index, count) // then assertAll( diff --git a/springboot/src/test/kotlin/com/goliath/emojihub/springboot/domain/post/service/PostServiceTest.kt b/springboot/src/test/kotlin/com/goliath/emojihub/springboot/domain/post/service/PostServiceTest.kt index 677ff2f4..ba80d523 100644 --- a/springboot/src/test/kotlin/com/goliath/emojihub/springboot/domain/post/service/PostServiceTest.kt +++ b/springboot/src/test/kotlin/com/goliath/emojihub/springboot/domain/post/service/PostServiceTest.kt @@ -93,15 +93,17 @@ internal class PostServiceTest { // given val username = "test_username" val wrongUsername = "wrong_username" + val index = 1 + val count = testDto.postSize val list = testDto.postList Mockito.`when`(userDao.existUser(username)).thenReturn(true) Mockito.`when`(userDao.existUser(wrongUsername)).thenReturn(false) - Mockito.`when`(postDao.getMyPosts(username)).thenReturn(list) + Mockito.`when`(postDao.getMyPosts(username, index, count)).thenReturn(list) // when - val result = postService.getMyPosts(username) + val result = postService.getMyPosts(username, index, count) val assertThrows = assertThrows(CustomHttp404::class.java) { - postService.getMyPosts(wrongUsername) + postService.getMyPosts(wrongUsername, index, count) } // then @@ -111,7 +113,7 @@ internal class PostServiceTest { ) verify(userDao, times(1)).existUser(username) verify(userDao, times(1)).existUser(wrongUsername) - verify(postDao, times(1)).getMyPosts(username) + verify(postDao, times(1)).getMyPosts(username, index, count) } @Test From 9de9458cc92bf641c9e216f983ef054567399406 Mon Sep 17 00:00:00 2001 From: peng-u-0807 Date: Sun, 26 Nov 2023 17:53:40 +0900 Subject: [PATCH 2/3] feat: add API connection for fetching user's posts&emojis --- .../data_sources/EmojiPagingSource.kt | 19 +++++++- .../emojihub/data_sources/PostPagingSource.kt | 16 ++++++- .../emojihub/data_sources/api/EmojiApi.kt | 14 ++++++ .../emojihub/data_sources/api/PostApi.kt | 5 ++ .../repositories/remote/EmojiRepository.kt | 19 +++++++- .../repositories/remote/PostRepository.kt | 11 ++++- .../goliath/emojihub/usecases/EmojiUseCase.kt | 31 ++++++++++++ .../goliath/emojihub/usecases/PostUseCase.kt | 15 ++++++ .../emojihub/viewmodels/EmojiViewModel.kt | 25 +++++++++- .../emojihub/viewmodels/PostViewModel.kt | 11 +++++ .../com/goliath/emojihub/views/ProfilePage.kt | 47 ++++++++++++------- 11 files changed, 187 insertions(+), 26 deletions(-) diff --git a/android/app/src/main/java/com/goliath/emojihub/data_sources/EmojiPagingSource.kt b/android/app/src/main/java/com/goliath/emojihub/data_sources/EmojiPagingSource.kt index e83b8c84..8774e6bc 100644 --- a/android/app/src/main/java/com/goliath/emojihub/data_sources/EmojiPagingSource.kt +++ b/android/app/src/main/java/com/goliath/emojihub/data_sources/EmojiPagingSource.kt @@ -6,14 +6,29 @@ import com.goliath.emojihub.data_sources.api.EmojiApi import com.goliath.emojihub.models.EmojiDto import javax.inject.Inject +enum class EmojiFetchType { + GENERAL, MY_CREATED, MY_SAVED +} + class EmojiPagingSource @Inject constructor( - private val api: EmojiApi + private val api: EmojiApi, + private val type: EmojiFetchType ): PagingSource() { override suspend fun load(params: LoadParams): LoadResult { val cursor = params.key ?: 1 val count = params.loadSize return try { - val response = api.fetchEmojiList(1, cursor, count).body() + val response: List? = when (type) { + EmojiFetchType.GENERAL -> { + api.fetchEmojiList(1, cursor, count).body() + } + EmojiFetchType.MY_CREATED -> { + api.fetchMyCreatedEmojiList(1, cursor, count).body() + } + EmojiFetchType.MY_SAVED -> { + api.fetchMySavedEmojiList(1, cursor, count).body() + } + } val data = response ?: listOf() LoadResult.Page( data = data, diff --git a/android/app/src/main/java/com/goliath/emojihub/data_sources/PostPagingSource.kt b/android/app/src/main/java/com/goliath/emojihub/data_sources/PostPagingSource.kt index f45dfc63..87799694 100644 --- a/android/app/src/main/java/com/goliath/emojihub/data_sources/PostPagingSource.kt +++ b/android/app/src/main/java/com/goliath/emojihub/data_sources/PostPagingSource.kt @@ -6,13 +6,25 @@ import com.goliath.emojihub.data_sources.api.PostApi import com.goliath.emojihub.models.PostDto import javax.inject.Inject +enum class PostFetchType { + GENERAL, MY +} + class PostPagingSource @Inject constructor( - private val api: PostApi + private val api: PostApi, + private val type: PostFetchType ): PagingSource() { override suspend fun load(params: LoadParams): LoadResult { val cursor = params.key ?: 1 return try { - val response = api.fetchPostList(cursor).body() + val response: List? = when (type) { + PostFetchType.GENERAL -> { + api.fetchPostList(cursor).body() + } + PostFetchType.MY -> { + api.fetchPostList(cursor).body() + } + } val data = response ?: listOf() LoadResult.Page( data = data, diff --git a/android/app/src/main/java/com/goliath/emojihub/data_sources/api/EmojiApi.kt b/android/app/src/main/java/com/goliath/emojihub/data_sources/api/EmojiApi.kt index a991404d..654d68ab 100644 --- a/android/app/src/main/java/com/goliath/emojihub/data_sources/api/EmojiApi.kt +++ b/android/app/src/main/java/com/goliath/emojihub/data_sources/api/EmojiApi.kt @@ -27,6 +27,20 @@ interface EmojiApi { @Path("id") id: String ): Response + @GET("emoji/me/created") + suspend fun fetchMyCreatedEmojiList( + @Query("sortByDate") sortByDate: Int, + @Query("index") index: Int, + @Query("count") count: Int + ): Response> + + @GET("emoji/me/saved") + suspend fun fetchMySavedEmojiList( + @Query("sortByDate") sortByDate: Int, + @Query("index") index: Int, + @Query("count") count: Int + ): Response> + @Multipart @POST("emoji") suspend fun uploadEmoji( diff --git a/android/app/src/main/java/com/goliath/emojihub/data_sources/api/PostApi.kt b/android/app/src/main/java/com/goliath/emojihub/data_sources/api/PostApi.kt index b32b8b06..7cd86e81 100644 --- a/android/app/src/main/java/com/goliath/emojihub/data_sources/api/PostApi.kt +++ b/android/app/src/main/java/com/goliath/emojihub/data_sources/api/PostApi.kt @@ -17,6 +17,11 @@ interface PostApi { @Query("index") index: Int ): Response> + @GET("post/me") + suspend fun fetchMyPostList( + @Query("index") index: Int + ): Response> + @GET("post") suspend fun getPostWithId( @Path("id") id: String diff --git a/android/app/src/main/java/com/goliath/emojihub/repositories/remote/EmojiRepository.kt b/android/app/src/main/java/com/goliath/emojihub/repositories/remote/EmojiRepository.kt index e5d0c71c..3ac410b6 100644 --- a/android/app/src/main/java/com/goliath/emojihub/repositories/remote/EmojiRepository.kt +++ b/android/app/src/main/java/com/goliath/emojihub/repositories/remote/EmojiRepository.kt @@ -7,6 +7,7 @@ import android.util.Log import androidx.paging.Pager import androidx.paging.PagingConfig import androidx.paging.PagingData +import com.goliath.emojihub.data_sources.EmojiFetchType import com.goliath.emojihub.data_sources.EmojiPagingSource import com.goliath.emojihub.data_sources.api.EmojiApi import com.goliath.emojihub.models.EmojiDto @@ -28,6 +29,8 @@ import javax.inject.Singleton interface EmojiRepository { suspend fun fetchEmojiList(): Flow> + suspend fun fetchMyCreatedEmojiList(): Flow> + suspend fun fetchMySavedEmojiList(): Flow> suspend fun getEmojiWithId(id: String): EmojiDto? suspend fun uploadEmoji(videoFile: File, emojiDto: UploadEmojiDto): Boolean suspend fun saveEmoji(id: String): Response @@ -43,7 +46,21 @@ class EmojiRepositoryImpl @Inject constructor( override suspend fun fetchEmojiList(): Flow> { return Pager( config = PagingConfig(pageSize = 10, initialLoadSize = 10, enablePlaceholders = false), - pagingSourceFactory = { EmojiPagingSource(emojiApi) } + pagingSourceFactory = { EmojiPagingSource(emojiApi, EmojiFetchType.GENERAL) } + ).flow + } + + override suspend fun fetchMyCreatedEmojiList(): Flow> { + return Pager( + config = PagingConfig(pageSize = 10, initialLoadSize = 10, enablePlaceholders = false), + pagingSourceFactory = { EmojiPagingSource(emojiApi, EmojiFetchType.MY_CREATED) } + ).flow + } + + override suspend fun fetchMySavedEmojiList(): Flow> { + return Pager( + config = PagingConfig(pageSize = 10, initialLoadSize = 10, enablePlaceholders = false), + pagingSourceFactory = { EmojiPagingSource(emojiApi, EmojiFetchType.MY_SAVED) } ).flow } diff --git a/android/app/src/main/java/com/goliath/emojihub/repositories/remote/PostRepository.kt b/android/app/src/main/java/com/goliath/emojihub/repositories/remote/PostRepository.kt index fe6b097d..20ffd20b 100644 --- a/android/app/src/main/java/com/goliath/emojihub/repositories/remote/PostRepository.kt +++ b/android/app/src/main/java/com/goliath/emojihub/repositories/remote/PostRepository.kt @@ -4,6 +4,7 @@ import android.util.Log import androidx.paging.Pager import androidx.paging.PagingConfig import androidx.paging.PagingData +import com.goliath.emojihub.data_sources.PostFetchType import com.goliath.emojihub.data_sources.PostPagingSource import com.goliath.emojihub.data_sources.api.PostApi import com.goliath.emojihub.models.PostDto @@ -15,6 +16,7 @@ import javax.inject.Singleton interface PostRepository { suspend fun fetchPostList(): Flow> + suspend fun fetchMyPostList(): Flow> suspend fun uploadPost(dto: UploadPostDto): Response suspend fun getPostWithId(id: String): PostDto? suspend fun editPost(id: String, content: String) @@ -28,7 +30,14 @@ class PostRepositoryImpl @Inject constructor( override suspend fun fetchPostList(): Flow> { return Pager( config = PagingConfig(pageSize = 10, enablePlaceholders = false), - pagingSourceFactory = { PostPagingSource(postApi) } + pagingSourceFactory = { PostPagingSource(postApi, PostFetchType.GENERAL) } + ).flow + } + + override suspend fun fetchMyPostList(): Flow> { + return Pager( + config = PagingConfig(pageSize = 10, enablePlaceholders = false), + pagingSourceFactory = { PostPagingSource(postApi, PostFetchType.MY) } ).flow } diff --git a/android/app/src/main/java/com/goliath/emojihub/usecases/EmojiUseCase.kt b/android/app/src/main/java/com/goliath/emojihub/usecases/EmojiUseCase.kt index 066ee3e2..66caebf5 100644 --- a/android/app/src/main/java/com/goliath/emojihub/usecases/EmojiUseCase.kt +++ b/android/app/src/main/java/com/goliath/emojihub/usecases/EmojiUseCase.kt @@ -20,8 +20,14 @@ import javax.inject.Singleton interface EmojiUseCase { val emojiList: StateFlow> + val myCreatedEmojiList: StateFlow> + val mySavedEmojiList: StateFlow> suspend fun updateEmojiList(data: PagingData) + suspend fun updateMyCreatedEmojiList(data: PagingData) + suspend fun updateMySavedEmojiList(data: PagingData) suspend fun fetchEmojiList(): Flow> + suspend fun fetchMyCreatedEmojiList(): Flow> + suspend fun fetchMySavedEmojiList(): Flow> suspend fun createEmoji(videoUri: Uri, topK: Int): List suspend fun uploadEmoji(emojiUnicode: String, emojiLabel: String, videoFile: File): Boolean suspend fun saveEmoji(id: String): Boolean @@ -39,13 +45,38 @@ class EmojiUseCaseImpl @Inject constructor( override val emojiList: StateFlow> get() = _emojiList + private val _myCreatedEmojiList = MutableStateFlow>(PagingData.empty()) + override val myCreatedEmojiList: StateFlow> + get() = _myCreatedEmojiList + + private val _mySavedEmojiList = MutableStateFlow>(PagingData.empty()) + override val mySavedEmojiList: StateFlow> + get() = _mySavedEmojiList + override suspend fun updateEmojiList(data: PagingData) { _emojiList.emit(data) } + + override suspend fun updateMyCreatedEmojiList(data: PagingData) { + _myCreatedEmojiList.emit(data) + } + + override suspend fun updateMySavedEmojiList(data: PagingData) { + _mySavedEmojiList.emit(data) + } + override suspend fun fetchEmojiList(): Flow> { return emojiRepository.fetchEmojiList().map { it.map { dto -> Emoji(dto) } } } + override suspend fun fetchMyCreatedEmojiList(): Flow> { + return emojiRepository.fetchMyCreatedEmojiList().map { it.map { dto -> Emoji(dto) } } + } + + override suspend fun fetchMySavedEmojiList(): Flow> { + return emojiRepository.fetchMySavedEmojiList().map { it.map { dto -> Emoji(dto) } } + } + override suspend fun createEmoji(videoUri: Uri, topK: Int): List { return x3dRepository.createEmoji(videoUri, topK) } diff --git a/android/app/src/main/java/com/goliath/emojihub/usecases/PostUseCase.kt b/android/app/src/main/java/com/goliath/emojihub/usecases/PostUseCase.kt index 2e65a634..df15b324 100644 --- a/android/app/src/main/java/com/goliath/emojihub/usecases/PostUseCase.kt +++ b/android/app/src/main/java/com/goliath/emojihub/usecases/PostUseCase.kt @@ -15,8 +15,11 @@ import javax.inject.Inject sealed interface PostUseCase { val postList: StateFlow> + val myPostList: StateFlow> suspend fun updatePostList(data: PagingData) + suspend fun updateMyPostList(data: PagingData) suspend fun fetchPostList(): Flow> + suspend fun fetchMyPostList(): Flow> suspend fun uploadPost(content: String): Boolean suspend fun getPostWithId(id: String): PostDto? suspend fun editPost(id: String, content: String) @@ -31,14 +34,26 @@ class PostUseCaseImpl @Inject constructor( override val postList: StateFlow> get() = _postList + private val _myPostList = MutableStateFlow>(PagingData.empty()) + override val myPostList: StateFlow> + get() = _myPostList + override suspend fun updatePostList(data: PagingData) { _postList.emit(data) } + override suspend fun updateMyPostList(data: PagingData) { + _myPostList.emit(data) + } + override suspend fun fetchPostList(): Flow> { return repository.fetchPostList().map { it.map { dto -> Post(dto) } } } + override suspend fun fetchMyPostList(): Flow> { + return repository.fetchMyPostList().map { it.map { dto -> Post(dto) } } + } + override suspend fun uploadPost(content: String): Boolean { val dto = UploadPostDto(content) val response = repository.uploadPost(dto) diff --git a/android/app/src/main/java/com/goliath/emojihub/viewmodels/EmojiViewModel.kt b/android/app/src/main/java/com/goliath/emojihub/viewmodels/EmojiViewModel.kt index e82620aa..0319ae9a 100644 --- a/android/app/src/main/java/com/goliath/emojihub/viewmodels/EmojiViewModel.kt +++ b/android/app/src/main/java/com/goliath/emojihub/viewmodels/EmojiViewModel.kt @@ -27,11 +27,12 @@ class EmojiViewModel @Inject constructor( var isBottomSheetShown by mutableStateOf(false) val emojiList = emojiUseCase.emojiList + val myCreatedEmojiList = emojiUseCase.myCreatedEmojiList + val mySavedEmojiList = emojiUseCase.mySavedEmojiList private val _topK = 3 - fun fetchEmojiList() - { + fun fetchEmojiList() { viewModelScope.launch { emojiUseCase.fetchEmojiList() .cachedIn(viewModelScope) @@ -41,6 +42,26 @@ class EmojiViewModel @Inject constructor( } } + fun fetchMyCreatedEmojiList() { + viewModelScope.launch { + emojiUseCase.fetchMyCreatedEmojiList() + .cachedIn(viewModelScope) + .collect { + emojiUseCase.updateMyCreatedEmojiList(it) + } + } + } + + fun fetchMySavedEmojiList() { + viewModelScope.launch { + emojiUseCase.fetchMySavedEmojiList() + .cachedIn(viewModelScope) + .collect { + emojiUseCase.updateMySavedEmojiList(it) + } + } + } + suspend fun createEmoji(videoUri: Uri): List { return withContext(Dispatchers.IO) { val createdEmojiList = emojiUseCase.createEmoji(videoUri, _topK) diff --git a/android/app/src/main/java/com/goliath/emojihub/viewmodels/PostViewModel.kt b/android/app/src/main/java/com/goliath/emojihub/viewmodels/PostViewModel.kt index 2cd3c6bf..06945776 100644 --- a/android/app/src/main/java/com/goliath/emojihub/viewmodels/PostViewModel.kt +++ b/android/app/src/main/java/com/goliath/emojihub/viewmodels/PostViewModel.kt @@ -14,6 +14,7 @@ class PostViewModel @Inject constructor( ): ViewModel() { val postList = postUseCase.postList + val myPostList = postUseCase.myPostList suspend fun fetchPostList() { viewModelScope.launch { @@ -25,6 +26,16 @@ class PostViewModel @Inject constructor( } } + suspend fun fetchMyPostList() { + viewModelScope.launch { + postUseCase.fetchMyPostList() + .cachedIn(viewModelScope) + .collect { + postUseCase.updateMyPostList(it) + } + } + } + suspend fun uploadPost(content: String): Boolean { return postUseCase.uploadPost(content) } diff --git a/android/app/src/main/java/com/goliath/emojihub/views/ProfilePage.kt b/android/app/src/main/java/com/goliath/emojihub/views/ProfilePage.kt index ccea324f..a099fa90 100644 --- a/android/app/src/main/java/com/goliath/emojihub/views/ProfilePage.kt +++ b/android/app/src/main/java/com/goliath/emojihub/views/ProfilePage.kt @@ -10,12 +10,11 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.items import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.verticalScroll import androidx.compose.material3.Divider import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -28,14 +27,13 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.hilt.navigation.compose.hiltViewModel +import androidx.paging.compose.collectAsLazyPagingItems import com.goliath.emojihub.LocalNavController import com.goliath.emojihub.NavigationDestination -import com.goliath.emojihub.models.createDummyEmoji -import com.goliath.emojihub.models.dummyEmoji -import com.goliath.emojihub.models.dummyPost import com.goliath.emojihub.ui.theme.Color import com.goliath.emojihub.ui.theme.Color.EmojiHubDetailLabel import com.goliath.emojihub.ui.theme.Color.White +import com.goliath.emojihub.viewmodels.EmojiViewModel import com.goliath.emojihub.viewmodels.PostViewModel import com.goliath.emojihub.viewmodels.UserViewModel import com.goliath.emojihub.views.components.CustomDialog @@ -55,12 +53,23 @@ fun ProfilePage( val userViewModel = hiltViewModel() val postViewModel = hiltViewModel() + val emojiViewModel = hiltViewModel() val currentUser = userViewModel.userState.collectAsState().value + val myPostList = postViewModel.myPostList.collectAsLazyPagingItems() + val myCreatedEmojiList = emojiViewModel.myCreatedEmojiList.collectAsLazyPagingItems() + val mySavedEmojiList = emojiViewModel.mySavedEmojiList.collectAsLazyPagingItems() + var showLogoutDialog by remember { mutableStateOf(false) } var showSignOutDialog by remember { mutableStateOf(false) } + LaunchedEffect(Unit) { + postViewModel.fetchPostList() + emojiViewModel.fetchMyCreatedEmojiList() + emojiViewModel.fetchMySavedEmojiList() + } + LazyColumn( Modifier.background(White) ) { @@ -106,9 +115,10 @@ fun ProfilePage( detailLabel = "count", navigateToDestination = { navController.navigate(NavigationDestination.MyPostList) } ) { - // TODO: should show my posts - items(listOf(dummyPost, dummyPost, dummyPost)) { - PreviewPostCell(post = it) + items(myPostList.itemCount) { index -> + myPostList[index]?.let { + PreviewPostCell(post = it) + } } } @@ -119,11 +129,14 @@ fun ProfilePage( ProfileMenuCellWithPreview( label = "내가 만든 이모지", detailLabel = "더보기", - navigateToDestination = { navController.navigate(NavigationDestination.MyEmojiList) }, - content = { - // should show my emojis + navigateToDestination = { navController.navigate(NavigationDestination.MyEmojiList) } + ) { + items(myCreatedEmojiList.itemCount) { index -> + myCreatedEmojiList[index]?.let { + EmojiCell(emoji = it, onSelected = {}) + } } - ) + } Spacer(modifier = Modifier.height(32.dp)) @@ -132,12 +145,10 @@ fun ProfilePage( detailLabel = "더보기", navigateToDestination = { navController.navigate(NavigationDestination.MySavedEmojiList) } ) { - // TODO: should show saved emoji list - items(listOf( - dummyEmoji, dummyEmoji, - dummyEmoji, dummyEmoji) - ) { - EmojiCell(emoji = it, onSelected = {}) + items(mySavedEmojiList.itemCount) { index -> + mySavedEmojiList[index]?.let { + EmojiCell(emoji = it, onSelected = {}) + } } } From 3bae6eb79c1dcee47d0b2808a474c35691b90dc7 Mon Sep 17 00:00:00 2001 From: peng-u-0807 Date: Wed, 29 Nov 2023 01:36:57 +0900 Subject: [PATCH 3/3] fix: fix typo (postList -> myPostList) --- .../emojihub/data_sources/PostPagingSource.kt | 2 +- .../com/goliath/emojihub/usecases/PostUseCase.kt | 1 + .../java/com/goliath/emojihub/views/ProfilePage.kt | 12 ++++-------- .../emojihub/views/components/PreviewPostCell.kt | 1 - 4 files changed, 6 insertions(+), 10 deletions(-) diff --git a/android/app/src/main/java/com/goliath/emojihub/data_sources/PostPagingSource.kt b/android/app/src/main/java/com/goliath/emojihub/data_sources/PostPagingSource.kt index 87799694..8f4fcf2c 100644 --- a/android/app/src/main/java/com/goliath/emojihub/data_sources/PostPagingSource.kt +++ b/android/app/src/main/java/com/goliath/emojihub/data_sources/PostPagingSource.kt @@ -22,7 +22,7 @@ class PostPagingSource @Inject constructor( api.fetchPostList(cursor).body() } PostFetchType.MY -> { - api.fetchPostList(cursor).body() + api.fetchMyPostList(cursor).body() } } val data = response ?: listOf() diff --git a/android/app/src/main/java/com/goliath/emojihub/usecases/PostUseCase.kt b/android/app/src/main/java/com/goliath/emojihub/usecases/PostUseCase.kt index df15b324..83fe79b7 100644 --- a/android/app/src/main/java/com/goliath/emojihub/usecases/PostUseCase.kt +++ b/android/app/src/main/java/com/goliath/emojihub/usecases/PostUseCase.kt @@ -25,6 +25,7 @@ sealed interface PostUseCase { suspend fun editPost(id: String, content: String) suspend fun deletePost(id: String) } + class PostUseCaseImpl @Inject constructor( private val repository: PostRepository, private val errorController: ApiErrorController diff --git a/android/app/src/main/java/com/goliath/emojihub/views/ProfilePage.kt b/android/app/src/main/java/com/goliath/emojihub/views/ProfilePage.kt index a099fa90..82662fdf 100644 --- a/android/app/src/main/java/com/goliath/emojihub/views/ProfilePage.kt +++ b/android/app/src/main/java/com/goliath/emojihub/views/ProfilePage.kt @@ -65,20 +65,16 @@ fun ProfilePage( var showSignOutDialog by remember { mutableStateOf(false) } LaunchedEffect(Unit) { - postViewModel.fetchPostList() + postViewModel.fetchMyPostList() emojiViewModel.fetchMyCreatedEmojiList() emojiViewModel.fetchMySavedEmojiList() } - LazyColumn( - Modifier.background(White) - ) { + LazyColumn(Modifier.background(White)) { item { TopNavigationBar("Profile", shouldNavigate = false) - Box( - modifier = Modifier.fillMaxSize() - ) { + Box(modifier = Modifier.fillMaxSize()) { if (currentUser?.accessToken.isNullOrEmpty()) { EmptyProfile() } else { @@ -112,7 +108,7 @@ fun ProfilePage( ProfileMenuCellWithPreview( label = "내가 작성한 포스트", - detailLabel = "count", + detailLabel = myPostList.itemCount.toString(), navigateToDestination = { navController.navigate(NavigationDestination.MyPostList) } ) { items(myPostList.itemCount) { index -> diff --git a/android/app/src/main/java/com/goliath/emojihub/views/components/PreviewPostCell.kt b/android/app/src/main/java/com/goliath/emojihub/views/components/PreviewPostCell.kt index d49773ab..33bd47be 100644 --- a/android/app/src/main/java/com/goliath/emojihub/views/components/PreviewPostCell.kt +++ b/android/app/src/main/java/com/goliath/emojihub/views/components/PreviewPostCell.kt @@ -4,7 +4,6 @@ import androidx.compose.foundation.border import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width