diff --git a/SodaLive/Sources/Agora/Agora.swift b/SodaLive/Sources/Agora/Agora.swift index 15a93e8..d1a70f6 100644 --- a/SodaLive/Sources/Agora/Agora.swift +++ b/SodaLive/Sources/Agora/Agora.swift @@ -111,6 +111,23 @@ final class Agora { rtmKit?.send(message, toPeer: peerId, completion: completion) } + func sendRawMessageToPeer(peerId: String, rawMessage: LiveRoomChatRawMessage, completion: AgoraRtmSendPeerMessageBlock? = nil, fail: (() -> Void)? = nil) { + let encoder = JSONEncoder() + let jsonMessageData = try? encoder.encode(rawMessage) + let option = AgoraRtmSendMessageOptions() + option.enableOfflineMessaging = false + option.enableHistoricalMessaging = false + + if let jsonMessageData = jsonMessageData { + let message = AgoraRtmRawMessage(rawData: jsonMessageData, description: "") + rtmKit?.send(message, toPeer: peerId, sendMessageOptions: option, completion: completion) + } else { + if let fail = fail { + fail() + } + } + } + func mute(_ isMute: Bool) { rtcEngine?.muteLocalAudioStream(isMute) } diff --git a/SodaLive/Sources/Content/Detail/ContentDetailView.swift b/SodaLive/Sources/Content/Detail/ContentDetailView.swift index 649ba07..18e6e80 100644 --- a/SodaLive/Sources/Content/Detail/ContentDetailView.swift +++ b/SodaLive/Sources/Content/Detail/ContentDetailView.swift @@ -323,7 +323,7 @@ struct ContentDetailView: View { } if viewModel.isShowDonationPopup { - LiveRoomDonationDialogView(isShowing: $viewModel.isShowDonationPopup, isAudioContentDonation: true) { can, comment in + LiveRoomDonationDialogView(isShowing: $viewModel.isShowDonationPopup, isAudioContentDonation: true) { can, comment, _ in viewModel.donation(can: can, comment: comment) } } diff --git a/SodaLive/Sources/Content/Detail/LiveRoomDonationDialogView.swift b/SodaLive/Sources/Content/Detail/LiveRoomDonationDialogView.swift index 0d91541..21c5f31 100644 --- a/SodaLive/Sources/Content/Detail/LiveRoomDonationDialogView.swift +++ b/SodaLive/Sources/Content/Detail/LiveRoomDonationDialogView.swift @@ -18,10 +18,11 @@ struct LiveRoomDonationDialogView: View { @State private var donationMessage = "" @State private var isShowErrorPopup = false @State private var errorMessage = "" + @State private var isSecret = false @Binding var isShowing: Bool let isAudioContentDonation: Bool - let onClickDonation: (Int, String) -> Void + let onClickDonation: (Int, String, Bool) -> Void @StateObject var keyboardHandler = KeyboardHandler() @@ -82,6 +83,27 @@ struct LiveRoomDonationDialogView: View { .foregroundColor(Color.gray90) .padding(.top, 16) + if !isAudioContentDonation { + HStack(spacing: 0) { + Spacer() + + HStack(spacing: 8) { + Image(isSecret ? "btn_select_checked" : "btn_select_normal") + .resizable() + .frame(width: 20, height: 20) + + Text("비밀후원") + .font(.custom(Font.medium.rawValue, size: 14.7)) + .foregroundColor(Color.grayee) + } + .onTapGesture { + isSecret.toggle() + } + } + .padding(.horizontal, 20) + .padding(.top, 16) + } + TextField("몇 캔을 후원할까요?", text: $donationCan) .font(.custom(Font.medium.rawValue, size: 13.3)) .foregroundColor(Color.grayee) @@ -221,7 +243,7 @@ struct LiveRoomDonationDialogView: View { .onTapGesture { if !donationCan.trimmingCharacters(in: .whitespaces).isEmpty, let can = Int(donationCan) { - onClickDonation(can, donationMessage) + onClickDonation(can, donationMessage, isSecret) isShowing = false } else { errorMessage = "1캔 이상 후원하실 수 있습니다." diff --git a/SodaLive/Sources/Live/LiveRepository.swift b/SodaLive/Sources/Live/LiveRepository.swift index 1ef872f..270a35c 100644 --- a/SodaLive/Sources/Live/LiveRepository.swift +++ b/SodaLive/Sources/Live/LiveRepository.swift @@ -73,8 +73,8 @@ final class LiveRepository { return api.requestPublisher(.getRoomInfo(roomId: roomId)) } - func donation(roomId: Int, can: Int, message: String = "") -> AnyPublisher { - return api.requestPublisher(.donation(request: LiveRoomDonationRequest(roomId: roomId, can: can, message: message))) + func donation(roomId: Int, can: Int, message: String = "", isSecret: Bool = false) -> AnyPublisher { + return api.requestPublisher(.donation(request: LiveRoomDonationRequest(roomId: roomId, can: can, message: message, isSecret: isSecret))) } func refundDonation(roomId: Int) -> AnyPublisher { diff --git a/SodaLive/Sources/Live/Room/Chat/LiveRoomChatRawMessage.swift b/SodaLive/Sources/Live/Room/Chat/LiveRoomChatRawMessage.swift index 49b7c22..cb6679a 100644 --- a/SodaLive/Sources/Live/Room/Chat/LiveRoomChatRawMessage.swift +++ b/SodaLive/Sources/Live/Room/Chat/LiveRoomChatRawMessage.swift @@ -9,7 +9,7 @@ import Foundation struct LiveRoomChatRawMessage: Codable { enum LiveRoomChatRawMessageType: String, Codable { - case DONATION, EDIT_ROOM_INFO, SET_MANAGER, TOGGLE_ROULETTE, ROULETTE_DONATION + case DONATION, SECRET_DONATION, EDIT_ROOM_INFO, SET_MANAGER, TOGGLE_ROULETTE, ROULETTE_DONATION } let type: LiveRoomChatRawMessageType diff --git a/SodaLive/Sources/Live/Room/Chat/LiveRoomDonationChatItemView.swift b/SodaLive/Sources/Live/Room/Chat/LiveRoomDonationChatItemView.swift index b228a76..b05beb8 100644 --- a/SodaLive/Sources/Live/Room/Chat/LiveRoomDonationChatItemView.swift +++ b/SodaLive/Sources/Live/Room/Chat/LiveRoomDonationChatItemView.swift @@ -43,7 +43,7 @@ struct LiveRoomDonationChatItemView: View { .font(.system(size: 15)) .foregroundColor(Color(hex: "fdca2f")) - Text("을 후원하셨습니다.") + Text(chatMessage.chat.contains("비밀") ? "을 비밀후원하셨습니다.💰🪙" : "을 후원하셨습니다.💰🪙") .font(.system(size: 15)) .foregroundColor(.white) } @@ -58,6 +58,7 @@ struct LiveRoomDonationChatItemView: View { .padding(13) .frame(width: screenSize().width - 86, alignment: .leading) .background( + chatMessage.chat.contains("비밀") ? Color(hex: "333333").opacity(0.8) : chatMessage.can >= 10000 ? Color(hex: "c25264").opacity(0.8) : chatMessage.can >= 5000 ? Color(hex: "d85e37").opacity(0.8) : chatMessage.can >= 1000 ? Color(hex: "d38c38").opacity(0.8) : diff --git a/SodaLive/Sources/Live/Room/LiveRoomDonationRequest.swift b/SodaLive/Sources/Live/Room/LiveRoomDonationRequest.swift index b437cad..4f8bec0 100644 --- a/SodaLive/Sources/Live/Room/LiveRoomDonationRequest.swift +++ b/SodaLive/Sources/Live/Room/LiveRoomDonationRequest.swift @@ -11,5 +11,6 @@ struct LiveRoomDonationRequest: Encodable { let roomId: Int let can: Int let message: String + var isSecret: Bool = false let container: String = "ios" } diff --git a/SodaLive/Sources/Live/Room/LiveRoomViewModel.swift b/SodaLive/Sources/Live/Room/LiveRoomViewModel.swift index 6f3a8e4..8c5c440 100644 --- a/SodaLive/Sources/Live/Room/LiveRoomViewModel.swift +++ b/SodaLive/Sources/Live/Room/LiveRoomViewModel.swift @@ -380,11 +380,11 @@ final class LiveRoomViewModel: NSObject, ObservableObject { } } - func donation(can: Int, message: String = "") { + func donation(can: Int, message: String = "", isSecret: Bool = false) { if can > 0 { isLoading = true - repository.donation(roomId: AppState.shared.roomId, can: can, message: message) + repository.donation(roomId: AppState.shared.roomId, can: can, message: message, isSecret: isSecret) .sink { result in switch result { case .finished: @@ -402,9 +402,16 @@ final class LiveRoomViewModel: NSObject, ObservableObject { self.isLoading = false if decoded.success { - let rawMessage = "\(can)캔을 후원하셨습니다." + var rawMessage = "" + + if isSecret { + rawMessage = "\(can)캔을 비밀후원하셨습니다.💰🪙" + } else { + rawMessage = "\(can)캔을 후원하셨습니다.💰🪙" + } + let donationRawMessage = LiveRoomChatRawMessage( - type: .DONATION, + type: isSecret ? .SECRET_DONATION : .DONATION, message: rawMessage, can: can, signature: decoded.data, @@ -414,36 +421,68 @@ final class LiveRoomViewModel: NSObject, ObservableObject { UserDefaults.set(UserDefaults.int(forKey: .can) - can, forKey: .can) - agora.sendRawMessageToGroup( - rawMessage: donationRawMessage, - completion: { [unowned self] errorCode in - if errorCode == .errorOk { - let (nickname, profileUrl) = self.getUserNicknameAndProfileUrl(accountId: UserDefaults.int(forKey: .userId)) - self.messages.append( - LiveRoomDonationChat( - profileUrl: profileUrl, - nickname: nickname, - chat: rawMessage, - can: can, - donationMessage: message + if isSecret { + agora.sendRawMessageToPeer( + peerId: String(liveRoomInfo!.creatorId), rawMessage: donationRawMessage, + completion: { [unowned self] errorCode in + if errorCode == .ok { + let (nickname, profileUrl) = self.getUserNicknameAndProfileUrl(accountId: UserDefaults.int(forKey: .userId)) + self.messages.append( + LiveRoomDonationChat( + profileUrl: profileUrl, + nickname: nickname, + chat: rawMessage, + can: can, + donationMessage: message + ) ) - ) - - totalDonationCan += can - addSignature(signature: decoded.data) - - self.messageChangeFlag.toggle() - if self.messages.count > 100 { - self.messages.remove(at: 0) + + addSignature(signature: decoded.data) + + self.messageChangeFlag.toggle() + if self.messages.count > 100 { + self.messages.remove(at: 0) + } + } else { + refundDonation() } - } else { + }, + fail: { [unowned self] in refundDonation() } - }, - fail: { [unowned self] in - refundDonation() - } - ) + ) + } else { + agora.sendRawMessageToGroup( + rawMessage: donationRawMessage, + completion: { [unowned self] errorCode in + if errorCode == .errorOk { + let (nickname, profileUrl) = self.getUserNicknameAndProfileUrl(accountId: UserDefaults.int(forKey: .userId)) + self.messages.append( + LiveRoomDonationChat( + profileUrl: profileUrl, + nickname: nickname, + chat: rawMessage, + can: can, + donationMessage: message + ) + ) + + totalDonationCan += can + addSignature(signature: decoded.data) + + self.messageChangeFlag.toggle() + if self.messages.count > 100 { + self.messages.remove(at: 0) + } + } else { + refundDonation() + } + }, + fail: { [unowned self] in + refundDonation() + } + ) + } } else { if let message = decoded.message { self.popupContent = message @@ -1858,6 +1897,31 @@ extension LiveRoomViewModel: AgoraRtmDelegate { self.startNoChatting() } } + + do { + let jsonDecoder = JSONDecoder() + let decoded = try jsonDecoder.decode(LiveRoomChatRawMessage.self, from: rawMessage.rawData) + let (nickname, profileUrl) = getUserNicknameAndProfileUrl(accountId: Int(peerId)!) + + if decoded.type == .SECRET_DONATION { + self.messages.append( + LiveRoomDonationChat( + profileUrl: profileUrl, + nickname: nickname, + chat: decoded.message, + can: decoded.can, + donationMessage: decoded.donationMessage ?? "" + ) + ) + + if let signature = decoded.signature { + self.addSignature(signature: signature) + } else if let imageUrl = decoded.signatureImageUrl { + self.addSignatureImage(imageUrl: imageUrl) + } + } + } catch { + } } } } diff --git a/SodaLive/Sources/Live/Room/V2/LiveRoomViewV2.swift b/SodaLive/Sources/Live/Room/V2/LiveRoomViewV2.swift index 7aa9ac2..cda0b85 100644 --- a/SodaLive/Sources/Live/Room/V2/LiveRoomViewV2.swift +++ b/SodaLive/Sources/Live/Room/V2/LiveRoomViewV2.swift @@ -203,10 +203,12 @@ struct LiveRoomViewV2: View { ) } - LiveRoomRightBottomButton( - imageName: "ic_donation", - onClick: { viewModel.isShowDonationPopup = true } - ) + if liveRoomInfo.creatorId != UserDefaults.int(forKey: .userId) { + LiveRoomRightBottomButton( + imageName: "ic_donation", + onClick: { viewModel.isShowDonationPopup = true } + ) + } LiveRoomRightBottomButton( imageName: "ic_donation_message_list", @@ -390,8 +392,8 @@ struct LiveRoomViewV2: View { } if viewModel.isShowDonationPopup { - LiveRoomDonationDialogView(isShowing: $viewModel.isShowDonationPopup, isAudioContentDonation: false) { can, message in - viewModel.donation(can: can, message: message) + LiveRoomDonationDialogView(isShowing: $viewModel.isShowDonationPopup, isAudioContentDonation: false) { can, message, isSecret in + viewModel.donation(can: can, message: message, isSecret: isSecret) } }