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

좋아요 기능 구현, Reponse(retrofit)에서 결과를 가져오는 확장함수 구현 #65

Merged
merged 2 commits into from
Jan 7, 2024
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
13 changes: 12 additions & 1 deletion app/src/main/java/com/whyranoid/walkie/KoinModules.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ import com.whyranoid.data.datasource.OtherUserPagingSource
import com.whyranoid.data.datasource.UserDataSourceImpl
import com.whyranoid.data.datasource.account.AccountDataSourceImpl
import com.whyranoid.data.datasource.account.AccountService
import com.whyranoid.data.datasource.community.CommunityDataSource
import com.whyranoid.data.datasource.community.CommunityDataSourceImpl
import com.whyranoid.data.datasource.community.CommunityService
import com.whyranoid.data.datasource.follow.FollowDataSourceImpl
import com.whyranoid.data.datasource.follow.FollowService
import com.whyranoid.data.datasource.post.PostDataSourceImpl
Expand All @@ -19,6 +22,7 @@ import com.whyranoid.data.datasource.running.RunningControlDataSourceImpl
import com.whyranoid.data.datasource.running.RunningService
import com.whyranoid.data.repository.AccountRepositoryImpl
import com.whyranoid.data.repository.ChallengeRepositoryImpl
import com.whyranoid.data.repository.CommunityRepositoryImpl
import com.whyranoid.data.repository.FollowRepositoryImpl
import com.whyranoid.data.repository.GpsRepositoryImpl
import com.whyranoid.data.repository.NetworkRepositoryImpl
Expand All @@ -35,6 +39,7 @@ import com.whyranoid.domain.datasource.RunningControlDataSource
import com.whyranoid.domain.datasource.UserDataSource
import com.whyranoid.domain.repository.AccountRepository
import com.whyranoid.domain.repository.ChallengeRepository
import com.whyranoid.domain.repository.CommunityRepository
import com.whyranoid.domain.repository.FollowRepository
import com.whyranoid.domain.repository.GpsRepository
import com.whyranoid.domain.repository.NetworkRepository
Expand All @@ -53,6 +58,7 @@ import com.whyranoid.domain.usecase.GetPostUseCase
import com.whyranoid.domain.usecase.GetUserBadgesUseCase
import com.whyranoid.domain.usecase.GetUserDetailUseCase
import com.whyranoid.domain.usecase.GetUserPostPreviewsUseCase
import com.whyranoid.domain.usecase.LikePostUseCase
import com.whyranoid.domain.usecase.SignOutUseCase
import com.whyranoid.domain.usecase.UploadPostUseCase
import com.whyranoid.domain.usecase.broadcast.AddGpsListener
Expand Down Expand Up @@ -106,7 +112,7 @@ val viewModelModule = module {
factory { AddPostViewModel(get()) }
factory { SearchFriendViewModel(get(), get(), get()) }
factory { DialogViewModel(get(), get(), get(), get(), get(), get()) }
factory { CommunityScreenViewModel(get(), get()) }
factory { CommunityScreenViewModel(get(), get(), get()) }
}

val repositoryModule = module {
Expand All @@ -120,6 +126,7 @@ val repositoryModule = module {
single<NetworkRepository> { NetworkRepositoryImpl(get()) }
single<GpsRepository> { GpsRepositoryImpl(get()) }
single<OtherUserRepository> { OtherUserRepositoryImpl(OtherUserPagingSource()) }
single<CommunityRepository> { CommunityRepositoryImpl(get()) }
}

val dataSourceModule = module {
Expand All @@ -129,6 +136,7 @@ val dataSourceModule = module {
single<AccountDataSource> { AccountDataSourceImpl(get()) }
single<FollowDataSource> { FollowDataSourceImpl(get()) }
single<RunningControlDataSource> { RunningControlDataSourceImpl(get()) }
single<CommunityDataSource> { CommunityDataSourceImpl(get()) }
}

val useCaseModule = module {
Expand Down Expand Up @@ -157,6 +165,7 @@ val useCaseModule = module {
single { UnFollowUseCase(get(), get()) }
single { GetMyFollowingUseCase(get(), get()) }
single { GetFollowingsPostsUseCase(get(), get()) }
single { LikePostUseCase(get(), get()) }
}

val databaseModule = module {
Expand Down Expand Up @@ -222,4 +231,6 @@ val networkModule = module {
single { get<Retrofit>().create(PostService::class.java) }

single { get<Retrofit>().create(RunningService::class.java) }

single { get<Retrofit>().create(CommunityService::class.java) }
Comment on lines 231 to +235
Copy link
Contributor

Choose a reason for hiding this comment

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

제가 잘 몰라서 질문 드립니다!
레트로핏 객체를 응집도에 따라서 여러개 생성하나요??
baseUrl이 다른것 이외에 차이점이 없더라고 여러개 생성하나요?

Copy link
Member Author

Choose a reason for hiding this comment

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

@yonghanJu
어... 이러면 안되지만 그렇게 되어있길래요...

Copy link
Member Author

Choose a reason for hiding this comment

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

근데 생각해보니까 서비스 객체들은 원래 여러 개 생성할 수 밖에 없지않나요

}
2 changes: 2 additions & 0 deletions data/src/main/java/com/whyranoid/data/API.kt
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ object API {

const val SEARCH = "api/community/search-nickname"

const val SEND_LIKE = "api/community/send-like"

object WalkingControl {
const val RUNNING_START = "api/walk/start"

Expand Down
12 changes: 12 additions & 0 deletions data/src/main/java/com/whyranoid/data/Utils.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.whyranoid.data

import retrofit2.Response

fun <T, R> Response<T>.getResult(transform: (T) -> R): R {
if (this.isSuccessful.not())
throw Exception(this.errorBody().toString())
else if (this.body() == null)
throw Exception(this.message())

return requireNotNull(this.body()?.let(transform) ?: throw Exception("empty response"))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.whyranoid.data.datasource.community

interface CommunityDataSource {

suspend fun likePost(postId: Long, likerId: Long): Result<Long>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.whyranoid.data.datasource.community

import com.whyranoid.data.getResult
import com.whyranoid.data.model.community.request.PostLikeRequest

class CommunityDataSourceImpl(
private val service: CommunityService
) : CommunityDataSource {
override suspend fun likePost(postId: Long, likerId: Long): Result<Long> {

return kotlin.runCatching {
val request = PostLikeRequest(likerId, postId)
val response = service.likePost(request)

response.getResult {
it.likerCount
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.whyranoid.data.datasource.community

import com.whyranoid.data.API
import com.whyranoid.data.model.community.request.PostLikeRequest
import com.whyranoid.data.model.community.response.PostLikeResponse
import retrofit2.Response
import retrofit2.http.Body
import retrofit2.http.POST

interface CommunityService {

@POST(API.SEND_LIKE)
suspend fun likePost(@Body postLikeRequest: PostLikeRequest): Response<PostLikeResponse>

}
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ class PostDataSourceImpl(private val postService: PostService) : PostDataSource
override suspend fun getMyFollowingsPost(uid: Long): Result<List<Post>> {
return kotlin.runCatching {
val posts = requireNotNull(postService.getPosts(uid).body())
posts.map { it.toPost() }
posts.map { it.toPost(uid) }
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.whyranoid.data.model.community.request

import com.google.gson.annotations.SerializedName

data class PostLikeRequest(
@SerializedName("likerId") val likerId: Long,
@SerializedName("postId") val postId: Long,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.whyranoid.data.model.community.response

import com.google.gson.annotations.SerializedName

data class LikerProfile(
@SerializedName("nickname") val nickname: String,
@SerializedName("profileImg") val profileImg: String,
@SerializedName("status") val status: String,
@SerializedName("walkieId") val walkieId: Long
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.whyranoid.data.model.community.response

import com.google.gson.annotations.SerializedName

data class PostLikeResponse(
@SerializedName("likerCount") val likerCount: Long,
@SerializedName("likerId") val likerId: Long,
@SerializedName("likerProfiles") val likerProfiles: List<LikerProfile>,
@SerializedName("postId") val postId: Long
)
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,14 @@ data class PostResponse(
)
}

fun toPost(): Post {
fun toPost(myUid: Long): Post {
return Post(
id = this.postId,
imageUrl = this.photo,
likeCount = this.likers.size,
contents = this.content,
author = this.poster.toUser(),
isLiked = this.likers.firstOrNull { it.uid == myUid } != null,
date = dateFormatter.parse(this.date.replace("T", " ")).time,
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.whyranoid.data.repository

import com.whyranoid.data.datasource.community.CommunityDataSource
import com.whyranoid.domain.repository.CommunityRepository

class CommunityRepositoryImpl(
private val communityDataSource: CommunityDataSource
): CommunityRepository {
override suspend fun likePost(postId: Long, likerId: Long): Result<Long> {
return communityDataSource.likePost(postId, likerId)
}
}
2 changes: 2 additions & 0 deletions domain/src/main/java/com/whyranoid/domain/model/post/Post.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ data class Post(
val id: Long,
val imageUrl: String,
val likeCount: Int,
val isLiked: Boolean,
val contents: String,
val author: User,
val date: Long = 0L,
Expand All @@ -17,6 +18,7 @@ data class Post(
likeCount = 3,
contents = "오늘도 상쾌한 달리기~",
author = User.DUMMY,
isLiked = false
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.whyranoid.domain.repository

interface CommunityRepository {

suspend fun likePost(postId: Long, likerId: Long): Result<Long>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.whyranoid.domain.usecase

import com.whyranoid.domain.repository.AccountRepository
import com.whyranoid.domain.repository.CommunityRepository
import kotlinx.coroutines.flow.first

class LikePostUseCase(
private val communityRepository: CommunityRepository,
private val accountRepository: AccountRepository
) {

suspend operator fun invoke(postId: Long): Result<Long> {
val uid = requireNotNull(accountRepository.uId.first())
return communityRepository.likePost(postId, uid)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,15 @@ import androidx.compose.ui.unit.dp
import com.whyranoid.domain.model.post.Post
import com.whyranoid.presentation.icons.buttoniconpack.CommentButtonIcon
import com.whyranoid.presentation.icons.buttoniconpack.HeartButtonIcon
import com.whyranoid.presentation.theme.WalkieColor
import com.whyranoid.presentation.theme.WalkieTypography

@Composable
fun PostContentItem(post: Post) {
fun PostContentItem(
post: Post,
onLikeClicked: (Long) -> Unit = {}
) {

Column(
modifier = Modifier
.fillMaxWidth()
Expand All @@ -43,11 +48,11 @@ fun PostContentItem(post: Post) {
modifier = Modifier
.size(20.dp)
.clickable {

}
,
onLikeClicked(post.id)
},
imageVector = HeartButtonIcon,
contentDescription = "좋아요 버튼",
tint = if (post.isLiked) WalkieColor.Primary else WalkieColor.GrayBorder
)

Spacer(modifier = Modifier.size(16.dp))
Expand All @@ -57,8 +62,7 @@ fun PostContentItem(post: Post) {
.size(20.dp)
.clickable {

}
,
},
imageVector = CommentButtonIcon,
contentDescription = "댓글 버튼",
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@ import coil.compose.AsyncImage
import com.whyranoid.domain.model.post.Post

@Composable
fun PostItem(post: Post) {
fun PostItem(
post: Post,
onLikeClicked: (Long) -> Unit = {},
) {
Column(
modifier = Modifier
.fillMaxHeight()
Expand All @@ -36,7 +39,9 @@ fun PostItem(post: Post) {
contentScale = ContentScale.Crop
)

PostContentItem(post)
PostContentItem(post) {
onLikeClicked(it)
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,9 @@ fun CommunityScreen(

state.posts.getDataOrNull()?.forEach { post ->
item {
PostItem(post = post)
PostItem(post = post) { postId ->
viewModel.likePost(postId)
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import com.whyranoid.domain.model.post.Post
import com.whyranoid.domain.model.user.User
import com.whyranoid.domain.usecase.GetMyFollowingUseCase
import com.whyranoid.domain.usecase.GetFollowingsPostsUseCase
import com.whyranoid.domain.usecase.LikePostUseCase
import com.whyranoid.presentation.model.UiState
import org.orbitmvi.orbit.ContainerHost
import org.orbitmvi.orbit.syntax.simple.intent
Expand All @@ -22,7 +23,8 @@ data class CommunityScreenState(

class CommunityScreenViewModel(
private val getMyFollowingUseCase: GetMyFollowingUseCase,
private val getFollowingsPostsUseCase: GetFollowingsPostsUseCase
private val getFollowingsPostsUseCase: GetFollowingsPostsUseCase,
private val likePostUseCase: LikePostUseCase
) : ViewModel(), ContainerHost<CommunityScreenState, CommunityScreenSideEffect> {

override val container =
Expand All @@ -44,7 +46,6 @@ class CommunityScreenViewModel(

fun getPosts() = intent {
val result = getFollowingsPostsUseCase()
println("결과 : $result")
result.onSuccess { posts ->
reduce {
state.copy(
Expand All @@ -56,4 +57,31 @@ class CommunityScreenViewModel(
}
}
}

fun likePost(postId: Long) = intent {
val result = likePostUseCase(postId)

result.onSuccess { updatedLikeCount ->

reduce {
state.copy(
posts = UiState.Success(
state.posts.getDataOrNull()?.map {
if (it.id == postId) {
it.copy(
likeCount = if (updatedLikeCount == -1L) it.likeCount - 1 else updatedLikeCount.toInt(),
isLiked = it.isLiked.not()
)
} else {
it
}
} ?: emptyList()
)
)
}
}.onFailure {
// TODO: Error handling
}

}
}
Loading