From e964679154dbcb3c4b506d13c95f09104e7637b3 Mon Sep 17 00:00:00 2001 From: klaus Date: Wed, 16 Oct 2024 18:06:38 +0900 Subject: [PATCH] =?UTF-8?q?=EB=9D=BC=EC=9D=B4=EB=B8=8C=20=EB=B0=A9=20-=20?= =?UTF-8?q?=ED=95=98=ED=8A=B8=20=ED=9B=84=EC=9B=90=20API=20=EC=97=B0?= =?UTF-8?q?=EA=B2=B0=20-=20=ED=95=98=ED=8A=B8=20=ED=9B=84=EC=9B=90=20?= =?UTF-8?q?=EC=84=B1=EA=B3=B5=EC=8B=9C=20=ED=95=98=ED=8A=B8=20=EC=95=A0?= =?UTF-8?q?=EB=8B=88=EB=A9=94=EC=9D=B4=EC=85=98=20=ED=98=B8=EC=B6=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle | 6 +- .../kr/co/vividnext/sodalive/live/LiveApi.kt | 8 +- .../vividnext/sodalive/live/LiveRepository.kt | 9 ++ .../sodalive/live/room/LiveRoomActivity.kt | 89 +++++++++++++++---- .../sodalive/live/room/LiveRoomViewModel.kt | 46 +++++++++- .../live/room/chat/LiveRoomChatRawMessage.kt | 5 +- .../room/like/LiveRoomLikeHeartRequest.kt | 10 +++ 7 files changed, 148 insertions(+), 25 deletions(-) create mode 100644 app/src/main/java/kr/co/vividnext/sodalive/live/room/like/LiveRoomLikeHeartRequest.kt diff --git a/app/build.gradle b/app/build.gradle index 8f6c413..cebaabe 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -35,8 +35,8 @@ android { applicationId "kr.co.vividnext.sodalive" minSdk 23 targetSdk 34 - versionCode 117 - versionName "1.21.2" + versionCode 118 + versionName "1.22.0" } buildTypes { @@ -159,4 +159,6 @@ dependencies { kapt "androidx.room:room-compiler:2.5.0" implementation "androidx.room:room-ktx:2.5.0" implementation "androidx.room:room-runtime:2.5.0" + + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4" } diff --git a/app/src/main/java/kr/co/vividnext/sodalive/live/LiveApi.kt b/app/src/main/java/kr/co/vividnext/sodalive/live/LiveApi.kt index 17938bb..36a745e 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/live/LiveApi.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/live/LiveApi.kt @@ -24,9 +24,9 @@ import kr.co.vividnext.sodalive.live.room.donation.LiveRoomDonationRequest import kr.co.vividnext.sodalive.live.room.donation.LiveRoomDonationResponse import kr.co.vividnext.sodalive.live.room.info.GetRoomInfoResponse import kr.co.vividnext.sodalive.live.room.kick_out.LiveRoomKickOutRequest +import kr.co.vividnext.sodalive.live.room.like.LiveRoomLikeHeartRequest import kr.co.vividnext.sodalive.live.room.profile.GetLiveRoomUserProfileResponse import kr.co.vividnext.sodalive.live.room.tag.GetLiveTagResponse -import kr.co.vividnext.sodalive.settings.ContentType import okhttp3.MultipartBody import okhttp3.RequestBody import retrofit2.http.Body @@ -213,4 +213,10 @@ interface LiveApi { @Body request: CancelLiveReservationRequest, @Header("Authorization") authHeader: String ): Single> + + @POST("/live/room/like-heart") + fun likeHeart( + @Body request: LiveRoomLikeHeartRequest, + @Header("Authorization") authHeader: String + ): Single> } diff --git a/app/src/main/java/kr/co/vividnext/sodalive/live/LiveRepository.kt b/app/src/main/java/kr/co/vividnext/sodalive/live/LiveRepository.kt index 1add11c..73fb188 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/live/LiveRepository.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/live/LiveRepository.kt @@ -17,6 +17,7 @@ import kr.co.vividnext.sodalive.live.room.donation.DeleteLiveRoomDonationMessage import kr.co.vividnext.sodalive.live.room.donation.LiveRoomDonationRequest import kr.co.vividnext.sodalive.live.room.donation.LiveRoomDonationResponse import kr.co.vividnext.sodalive.live.room.kick_out.LiveRoomKickOutRequest +import kr.co.vividnext.sodalive.live.room.like.LiveRoomLikeHeartRequest import kr.co.vividnext.sodalive.live.room.menu.MenuApi import kr.co.vividnext.sodalive.user.CreatorFollowRequestRequest import kr.co.vividnext.sodalive.user.UserApi @@ -242,4 +243,12 @@ class LiveRepository( creatorId = creatorId, authHeader = token ) + + fun likeHeart(roomId: Long, token: String) = api.likeHeart( + request = LiveRoomLikeHeartRequest( + roomId = roomId, + container = "aos" + ), + authHeader = token + ) } diff --git a/app/src/main/java/kr/co/vividnext/sodalive/live/room/LiveRoomActivity.kt b/app/src/main/java/kr/co/vividnext/sodalive/live/room/LiveRoomActivity.kt index 2986414..0be1ad7 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/live/room/LiveRoomActivity.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/live/room/LiveRoomActivity.kt @@ -33,6 +33,7 @@ import androidx.activity.OnBackPressedCallback import androidx.activity.result.contract.ActivityResultContracts import androidx.appcompat.widget.PopupMenu import androidx.core.content.ContextCompat +import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import coil.transform.CircleCropTransformation @@ -53,6 +54,7 @@ import io.agora.rtm.RtmChannelMember import io.agora.rtm.RtmClientListener import io.agora.rtm.RtmMessage import io.agora.rtm.RtmMessageType +import kotlinx.coroutines.launch import kr.co.vividnext.sodalive.R import kr.co.vividnext.sodalive.agora.Agora import kr.co.vividnext.sodalive.base.BaseActivity @@ -124,6 +126,7 @@ class LiveRoomActivity : BaseActivity(ActivityLiveRoomB private var isMicrophoneMute = false private var isSpeaker = false + private var isHost = false private var isNoChatting = false private var remainingNoChattingTime = noChattingTime @@ -530,8 +533,13 @@ class LiveRoomActivity : BaseActivity(ActivityLiveRoomB return (second * 1000).toLong() } - private fun addHeartAnimation(button: View) { + private fun addHeartAnimation() { // 버튼의 위치 + val button = if (isHost) { + binding.flRouletteSettings + } else { + binding.flLikeHeart + } val buttonPosition = IntArray(2) button.getLocationInWindow(buttonPosition) @@ -1004,12 +1012,10 @@ class LiveRoomActivity : BaseActivity(ActivityLiveRoomB binding.ivCreatorFollow.visibility = View.GONE } - initLikeHeartButton(isHost = response.creatorId == SharedPreferenceManager.userId) - initRouletteSettingButton(isHost = response.creatorId == SharedPreferenceManager.userId) - activatingRouletteButton( - isHost = response.creatorId == SharedPreferenceManager.userId, - isActiveRoulette = response.isActiveRoulette - ) + isHost = response.creatorId == SharedPreferenceManager.userId + initLikeHeartButton() + initRouletteSettingButton() + activatingRouletteButton(isActiveRoulette = response.isActiveRoulette) if (response.menuPan.isNotBlank()) { binding.tvMenuPan.visibility = View.VISIBLE @@ -1094,16 +1100,51 @@ class LiveRoomActivity : BaseActivity(ActivityLiveRoomB } } - private fun initLikeHeartButton(isHost: Boolean) { + private fun initLikeHeartButton() { if (!isHost) { binding.flLikeHeart.visibility = View.VISIBLE - binding.flLikeHeart.setOnClickListener { addHeartAnimation(it) } + binding.flLikeHeart.setOnClickListener { + binding.flLikeHeart.isEnabled = false + viewModel.likeHeart( + roomId = roomId, + onSuccess = { + val donationRawMessage = Gson().toJson( + LiveRoomChatRawMessage( + type = LiveRoomChatRawMessageType.HEART_DONATION, + message = "", + can = 1, + signature = null, + signatureImageUrl = null, + donationMessage = null + ) + ) + + agora.sendRawMessageToGroup( + rawMessage = donationRawMessage.toByteArray(), + onSuccess = { + handler.post { + addHeartAnimation() + lifecycleScope.launch { viewModel.addHeartDonation() } + } + }, + onFailure = { + viewModel.refundDonation(roomId) + } + ) + + binding.flLikeHeart.isEnabled = true + }, + onFailure = { + binding.flLikeHeart.isEnabled = true + } + ) + } } else { binding.flLikeHeart.visibility = View.GONE } } - private fun initRouletteSettingButton(isHost: Boolean) { + private fun initRouletteSettingButton() { if (isHost) { binding.flRouletteSettings.visibility = View.VISIBLE binding.flRouletteSettings.setOnClickListener { @@ -1119,7 +1160,7 @@ class LiveRoomActivity : BaseActivity(ActivityLiveRoomB } } - private fun activatingRouletteButton(isHost: Boolean, isActiveRoulette: Boolean) { + private fun activatingRouletteButton(isActiveRoulette: Boolean) { if (!isHost && isActiveRoulette) { binding.flRoulette.visibility = View.VISIBLE binding.flRoulette.setOnClickListener { @@ -1533,7 +1574,7 @@ class LiveRoomActivity : BaseActivity(ActivityLiveRoomB ) ) invalidateChat() - viewModel.addDonationCan(can) + lifecycleScope.launch { viewModel.addDonationCan(can) } addSignature(signature) } }, @@ -1574,7 +1615,7 @@ class LiveRoomActivity : BaseActivity(ActivityLiveRoomB ) ) invalidateChat() - viewModel.addDonationCan(can) + lifecycleScope.launch { viewModel.addDonationCan(can) } } }, onFailure = { @@ -1641,7 +1682,9 @@ class LiveRoomActivity : BaseActivity(ActivityLiveRoomB ) ) invalidateChat() - viewModel.addDonationCan(rawMessage.can) + lifecycleScope.launch { + viewModel.addDonationCan(rawMessage.can) + } if (rawMessage.signature != null) { addSignature(rawMessage.signature) @@ -1666,9 +1709,6 @@ class LiveRoomActivity : BaseActivity(ActivityLiveRoomB LiveRoomChatRawMessageType.TOGGLE_ROULETTE -> { handler.post { activatingRouletteButton( - isHost = viewModel - .roomInfoResponse - .creatorId == SharedPreferenceManager.userId, isActiveRoulette = rawMessage.isActiveRoulette ?: false ) } @@ -1684,7 +1724,16 @@ class LiveRoomActivity : BaseActivity(ActivityLiveRoomB ) ) invalidateChat() - viewModel.addDonationCan(rawMessage.can) + lifecycleScope.launch { + viewModel.addDonationCan(rawMessage.can) + } + } + } + + LiveRoomChatRawMessageType.HEART_DONATION -> { + handler.post { + addHeartAnimation() + lifecycleScope.launch { viewModel.addHeartDonation() } } } @@ -2009,7 +2058,9 @@ class LiveRoomActivity : BaseActivity(ActivityLiveRoomB ) ) invalidateChat() - viewModel.addDonationCan(message.can) + lifecycleScope.launch { + viewModel.addDonationCan(message.can) + } if (message.signature != null) { addSignature(message.signature) diff --git a/app/src/main/java/kr/co/vividnext/sodalive/live/room/LiveRoomViewModel.kt b/app/src/main/java/kr/co/vividnext/sodalive/live/room/LiveRoomViewModel.kt index 532ec7e..dba5c60 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/live/room/LiveRoomViewModel.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/live/room/LiveRoomViewModel.kt @@ -13,6 +13,8 @@ import com.google.gson.Gson import com.orhanobut.logger.Logger import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers import io.reactivex.rxjava3.schedulers.Schedulers +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock import kr.co.vividnext.sodalive.base.BaseViewModel import kr.co.vividnext.sodalive.common.SharedPreferenceManager import kr.co.vividnext.sodalive.live.LiveRepository @@ -100,6 +102,8 @@ class LiveRoomViewModel( private val blockedMemberIdList: MutableList = mutableListOf() + val mutex = Mutex() + fun getUserNickname(memberId: Int): String { for (manager in roomInfoResponse.managerList) { if (manager.id.toInt() == memberId) { @@ -562,6 +566,36 @@ class LiveRoomViewModel( ) } + fun likeHeart(roomId: Long, onSuccess: () -> Unit, onFailure: () -> Unit) { + compositeDisposable.add( + repository.likeHeart(roomId, token = "Bearer ${SharedPreferenceManager.token}") + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + { + if (it.success) { + SharedPreferenceManager.can -= 1 + onSuccess() + } else { + if (it.message != null) { + _toastLiveData.postValue(it.message) + } else { + _toastLiveData.postValue( + "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요." + ) + } + onFailure() + } + }, + { + it.message?.let { message -> Logger.e(message) } + _toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.") + onFailure() + } + ) + ) + } + fun donation( roomId: Long, can: Int, @@ -641,8 +675,16 @@ class LiveRoomViewModel( ) } - fun addDonationCan(can: Int) { - _totalDonationCan.postValue(totalDonationCan.value!! + can) + suspend fun addDonationCan(can: Int) { + mutex.withLock { + _totalDonationCan.postValue(totalDonationCan.value!! + can) + } + } + + suspend fun addHeartDonation() { + mutex.withLock { + _totalLikeHeart.postValue(totalLikeHeart.value!! + 1) + } } fun donationStatus(roomId: Long, onSuccess: (GetLiveRoomDonationStatusResponse) -> Unit) { diff --git a/app/src/main/java/kr/co/vividnext/sodalive/live/room/chat/LiveRoomChatRawMessage.kt b/app/src/main/java/kr/co/vividnext/sodalive/live/room/chat/LiveRoomChatRawMessage.kt index 03659e7..93265b1 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/live/room/chat/LiveRoomChatRawMessage.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/live/room/chat/LiveRoomChatRawMessage.kt @@ -35,5 +35,8 @@ enum class LiveRoomChatRawMessageType { TOGGLE_ROULETTE, @SerializedName("ROULETTE_DONATION") - ROULETTE_DONATION + ROULETTE_DONATION, + + @SerializedName("HEART_DONATION") + HEART_DONATION } diff --git a/app/src/main/java/kr/co/vividnext/sodalive/live/room/like/LiveRoomLikeHeartRequest.kt b/app/src/main/java/kr/co/vividnext/sodalive/live/room/like/LiveRoomLikeHeartRequest.kt new file mode 100644 index 0000000..fa535ed --- /dev/null +++ b/app/src/main/java/kr/co/vividnext/sodalive/live/room/like/LiveRoomLikeHeartRequest.kt @@ -0,0 +1,10 @@ +package kr.co.vividnext.sodalive.live.room.like + +import androidx.annotation.Keep +import com.google.gson.annotations.SerializedName + +@Keep +data class LiveRoomLikeHeartRequest( + @SerializedName("roomId") val roomId: Long, + @SerializedName("container") val container: String +)