라이브 방
- 하트 후원 API 연결 - 하트 후원 성공시 하트 애니메이션 호출 - 하트 후원 성공시 채팅으로 알림
This commit is contained in:
parent
9fa1bf9f64
commit
17b4516b87
|
@ -37,6 +37,8 @@ enum LiveApi {
|
|||
case deleteDonationMessage(roomId: Int, messageUUID: String)
|
||||
case getUserProfile(roomId: Int, userId: Int)
|
||||
case getAllMenuPreset(creatorId: Int)
|
||||
case likeHeart(request: LiveRoomLikeHeartRequest)
|
||||
case getTotalHeartCount(roomId: Int)
|
||||
}
|
||||
|
||||
extension LiveApi: TargetType {
|
||||
|
@ -129,15 +131,21 @@ extension LiveApi: TargetType {
|
|||
|
||||
case .getAllMenuPreset:
|
||||
return "/live/room/menu/all"
|
||||
|
||||
case .likeHeart:
|
||||
return "/live/room/like-heart"
|
||||
|
||||
case .getTotalHeartCount(let roomId):
|
||||
return "/live/room/\(roomId)/heart-total"
|
||||
}
|
||||
}
|
||||
|
||||
var method: Moya.Method {
|
||||
switch self {
|
||||
case .roomList, .recentVisitRoomUsers, .getReservations, .getReservation, .getRoomDetail, .getTags, .getRecentRoomInfo, .getRoomInfo, .donationStatus, .donationTotal, .getDonationMessageList, .getUserProfile, .getAllMenuPreset:
|
||||
case .roomList, .recentVisitRoomUsers, .getReservations, .getReservation, .getRoomDetail, .getTags, .getRecentRoomInfo, .getRoomInfo, .donationStatus, .donationTotal, .getDonationMessageList, .getUserProfile, .getAllMenuPreset, .getTotalHeartCount:
|
||||
return .get
|
||||
|
||||
case .makeReservation, .enterRoom, .createRoom, .quitRoom, .donation, .refundDonation, .kickOut:
|
||||
case .makeReservation, .enterRoom, .createRoom, .quitRoom, .donation, .refundDonation, .kickOut, .likeHeart:
|
||||
return .post
|
||||
|
||||
case .setListener, .setSpeaker, .setManager, .cancelReservation, .startLive, .cancelRoom, .editLiveRoomInfo:
|
||||
|
@ -166,7 +174,7 @@ extension LiveApi: TargetType {
|
|||
parameters: parameters,
|
||||
encoding: URLEncoding.queryString)
|
||||
|
||||
case .recentVisitRoomUsers, .getTags, .getRecentRoomInfo, .getRoomInfo, .refundDonation, .donationStatus, .donationTotal, .getUserProfile:
|
||||
case .recentVisitRoomUsers, .getTags, .getRecentRoomInfo, .getRoomInfo, .refundDonation, .donationStatus, .donationTotal, .getUserProfile, .getTotalHeartCount:
|
||||
return .requestPlain
|
||||
|
||||
case .getReservations(let isActive):
|
||||
|
@ -233,6 +241,9 @@ extension LiveApi: TargetType {
|
|||
|
||||
case .getAllMenuPreset(let creatorId):
|
||||
return .requestParameters(parameters: ["creatorId" : creatorId], encoding: URLEncoding.queryString)
|
||||
|
||||
case .likeHeart(let request):
|
||||
return .requestJSONEncodable(request)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -120,4 +120,12 @@ final class LiveRepository {
|
|||
func getAllMenuPreset(creatorId: Int) -> AnyPublisher<Response, MoyaError> {
|
||||
return api.requestPublisher(.getAllMenuPreset(creatorId: creatorId))
|
||||
}
|
||||
|
||||
func likeHeart(roomId: Int) -> AnyPublisher<Response, MoyaError> {
|
||||
return api.requestPublisher(.likeHeart(request: LiveRoomLikeHeartRequest(roomId: roomId)))
|
||||
}
|
||||
|
||||
func getTotalHeartCount(roomId: Int) -> AnyPublisher<Response, MoyaError> {
|
||||
return api.requestPublisher(.getTotalHeartCount(roomId: roomId))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
import Foundation
|
||||
|
||||
enum LiveRoomChatType: String {
|
||||
case CHAT, DONATION, JOIN, ROULETTE_DONATION
|
||||
case CHAT, DONATION, JOIN, ROULETTE_DONATION, HEART
|
||||
}
|
||||
|
||||
protocol LiveRoomChat {
|
||||
|
@ -48,3 +48,9 @@ struct LiveRoomJoinChat: LiveRoomChat {
|
|||
|
||||
var type: LiveRoomChatType = .JOIN
|
||||
}
|
||||
|
||||
struct LiveRoomHeartDonationChat: LiveRoomChat {
|
||||
let nickname: String
|
||||
|
||||
var type: LiveRoomChatType = .HEART
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ import Foundation
|
|||
|
||||
struct LiveRoomChatRawMessage: Codable {
|
||||
enum LiveRoomChatRawMessageType: String, Codable {
|
||||
case DONATION, SECRET_DONATION, EDIT_ROOM_INFO, SET_MANAGER, TOGGLE_ROULETTE, ROULETTE_DONATION
|
||||
case DONATION, SECRET_DONATION, EDIT_ROOM_INFO, SET_MANAGER, TOGGLE_ROULETTE, ROULETTE_DONATION, HEART_DONATION
|
||||
}
|
||||
|
||||
let type: LiveRoomChatRawMessageType
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
//
|
||||
// LiveRoomHeartDonationChatItemView.swift
|
||||
// SodaLive
|
||||
//
|
||||
// Created by klaus on 10/24/24.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct LiveRoomHeartDonationChatItemView: View {
|
||||
|
||||
let chatMessage: LiveRoomHeartDonationChat
|
||||
|
||||
var body: some View {
|
||||
HStack(spacing: 0) {
|
||||
Text("'")
|
||||
.font(.system(size: 12))
|
||||
.foregroundColor(Color.gray11)
|
||||
|
||||
Text(chatMessage.nickname)
|
||||
.font(.system(size: 12, weight: .bold))
|
||||
.foregroundColor(Color(hex: "ec3aa6"))
|
||||
|
||||
Text("'님이 마음을 전했습니다 : 💕")
|
||||
.font(.system(size: 12))
|
||||
.foregroundColor(Color.gray11)
|
||||
}
|
||||
.padding(.vertical, 6.7)
|
||||
.frame(width: screenSize().width - 86)
|
||||
.background(Color.white.opacity(0.7))
|
||||
.cornerRadius(4.7)
|
||||
.padding(.leading, 20)
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
LiveRoomHeartDonationChatItemView(chatMessage: LiveRoomHeartDonationChat(nickname: "닉네임"))
|
||||
}
|
|
@ -118,6 +118,7 @@ final class LiveRoomViewModel: NSObject, ObservableObject {
|
|||
}
|
||||
|
||||
@Published var totalDonationCan = 0
|
||||
@Published var totalHeartCount = 0
|
||||
@Published var donationMessageList = [LiveRoomDonationMessage]()
|
||||
@Published var donationMessageCount = 0
|
||||
|
||||
|
@ -361,6 +362,7 @@ final class LiveRoomViewModel: NSObject, ObservableObject {
|
|||
)
|
||||
|
||||
getTotalDonationCan()
|
||||
getTotalHeartCount()
|
||||
|
||||
if data.isAdult && !UserDefaults.bool(forKey: .auth) {
|
||||
changeIsAdult = true
|
||||
|
@ -1133,6 +1135,32 @@ final class LiveRoomViewModel: NSObject, ObservableObject {
|
|||
}
|
||||
}
|
||||
|
||||
private func getTotalHeartCount() {
|
||||
repository.getTotalHeartCount(roomId: AppState.shared.roomId)
|
||||
.sink { result in
|
||||
switch result {
|
||||
case .finished:
|
||||
DEBUG_LOG("finish")
|
||||
case .failure(let error):
|
||||
ERROR_LOG(error.localizedDescription)
|
||||
}
|
||||
} receiveValue: { [unowned self] response in
|
||||
self.isLoading = false
|
||||
let responseData = response.data
|
||||
|
||||
do {
|
||||
let jsonDecoder = JSONDecoder()
|
||||
let decoded = try jsonDecoder.decode(ApiResponse<GetLiveRoomHeartTotalResponse>.self, from: responseData)
|
||||
|
||||
if let data = decoded.data, decoded.success {
|
||||
self.totalHeartCount = data.totalHeartCount
|
||||
}
|
||||
} catch {
|
||||
}
|
||||
}
|
||||
.store(in: &subscription)
|
||||
}
|
||||
|
||||
func getTotalDonationCan() {
|
||||
repository.getTotalDoantionCan(roomId: AppState.shared.roomId)
|
||||
.sink { result in
|
||||
|
@ -1821,11 +1849,61 @@ final class LiveRoomViewModel: NSObject, ObservableObject {
|
|||
if isAvailableLikeHeart {
|
||||
if !isLoadingLikeHeart {
|
||||
isLoadingLikeHeart = true
|
||||
addHeart()
|
||||
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 1.5) { [unowned self] in
|
||||
self.isLoadingLikeHeart = false
|
||||
}
|
||||
repository.likeHeart(roomId: AppState.shared.roomId)
|
||||
.sink { result in
|
||||
switch result {
|
||||
case .finished:
|
||||
DEBUG_LOG("finish")
|
||||
case .failure(let error):
|
||||
ERROR_LOG(error.localizedDescription)
|
||||
}
|
||||
} receiveValue: { [unowned self] response in
|
||||
self.isLoadingLikeHeart = false
|
||||
let responseData = response.data
|
||||
|
||||
do {
|
||||
let jsonDecoder = JSONDecoder()
|
||||
let decoded = try jsonDecoder.decode(ApiResponseWithoutData.self, from: responseData)
|
||||
|
||||
if decoded.success {
|
||||
UserDefaults.set(UserDefaults.int(forKey: .can) - 1, forKey: .can)
|
||||
|
||||
let donationRawMessage = LiveRoomChatRawMessage(
|
||||
type: .HEART_DONATION,
|
||||
message: "",
|
||||
can: 1,
|
||||
donationMessage: nil
|
||||
)
|
||||
|
||||
agora.sendRawMessageToGroup(
|
||||
rawMessage: donationRawMessage,
|
||||
completion: { [unowned self] errorCode in
|
||||
if errorCode == .errorOk {
|
||||
let (nickname, _) = self.getUserNicknameAndProfileUrl(accountId: UserDefaults.int(forKey: .userId))
|
||||
self.messages.append(LiveRoomHeartDonationChat(nickname: nickname))
|
||||
|
||||
totalHeartCount += 1
|
||||
addHeart()
|
||||
|
||||
self.messageChangeFlag.toggle()
|
||||
if self.messages.count > 100 {
|
||||
self.messages.remove(at: 0)
|
||||
}
|
||||
} else {
|
||||
refundDonation()
|
||||
}
|
||||
},
|
||||
fail: { [unowned self] in
|
||||
refundDonation()
|
||||
}
|
||||
)
|
||||
}
|
||||
} catch {
|
||||
refundDonation()
|
||||
}
|
||||
}
|
||||
.store(in: &subscription)
|
||||
}
|
||||
} else {
|
||||
isShowNoticeLikeHeart = true
|
||||
|
@ -2114,6 +2192,10 @@ extension LiveRoomViewModel: AgoraRtmChannelDelegate {
|
|||
self.isActiveRoulette = decoded.isActiveRoulette!
|
||||
} else if decoded.type == .EDIT_ROOM_INFO || decoded.type == .SET_MANAGER {
|
||||
self.getRoomInfo()
|
||||
} else if decoded.type == .HEART_DONATION {
|
||||
self.messages.append(LiveRoomHeartDonationChat(nickname: nickname))
|
||||
self.totalHeartCount += decoded.can
|
||||
self.addHeart()
|
||||
}
|
||||
} catch {
|
||||
}
|
||||
|
|
|
@ -28,6 +28,10 @@ struct LiveRoomChatView: View {
|
|||
let chatMessage = messages[index] as! LiveRoomJoinChat
|
||||
LiveRoomJoinChatItemView(chatMessage: chatMessage)
|
||||
|
||||
case LiveRoomChatType.HEART:
|
||||
let chatMessage = messages[index] as! LiveRoomHeartDonationChat
|
||||
LiveRoomHeartDonationChatItemView(chatMessage: chatMessage)
|
||||
|
||||
default:
|
||||
let chatMessage = messages[index] as! LiveRoomNormalChat
|
||||
LiveRoomChatItemView(
|
||||
|
|
|
@ -10,6 +10,7 @@ import SwiftUI
|
|||
struct LiveRoomInfoGuestView: View {
|
||||
|
||||
let title: String
|
||||
let totalHeart: Int
|
||||
let totalDonationCan: Int
|
||||
|
||||
let isOnBg: Bool
|
||||
|
@ -163,7 +164,23 @@ struct LiveRoomInfoGuestView: View {
|
|||
|
||||
Spacer()
|
||||
|
||||
HStack(spacing: 2.7) {
|
||||
HStack(spacing: 6.7) {
|
||||
Image("ic_heart_pink")
|
||||
.resizable()
|
||||
.frame(width: 12, height: 12)
|
||||
|
||||
Text("\(totalHeart)")
|
||||
.font(.custom(Font.medium.rawValue, size: 12))
|
||||
.foregroundColor(.graybb)
|
||||
}
|
||||
.padding(.horizontal, 11)
|
||||
.padding(.vertical, 5.3)
|
||||
.overlay(
|
||||
RoundedRectangle(cornerRadius: 5.3)
|
||||
.stroke(Color.graybb, lineWidth: 1)
|
||||
)
|
||||
|
||||
HStack(spacing: 6.7) {
|
||||
Image("ic_can")
|
||||
.resizable()
|
||||
.frame(width: 12, height: 12)
|
||||
|
@ -202,6 +219,7 @@ struct LiveRoomInfoGuestView_Previews: PreviewProvider {
|
|||
static var previews: some View {
|
||||
LiveRoomInfoGuestView(
|
||||
title: "qwer",
|
||||
totalHeart: 1234,
|
||||
totalDonationCan: 123456,
|
||||
isOnBg: true,
|
||||
isOnNotice: false,
|
||||
|
|
|
@ -11,6 +11,7 @@ import Kingfisher
|
|||
struct LiveRoomInfoHostView: View {
|
||||
|
||||
let title: String
|
||||
let totalHeart: Int
|
||||
let totalDonationCan: Int
|
||||
let participantsCount: Int
|
||||
|
||||
|
@ -161,7 +162,23 @@ struct LiveRoomInfoHostView: View {
|
|||
|
||||
Spacer()
|
||||
|
||||
HStack(spacing: 2.7) {
|
||||
HStack(spacing: 6.7) {
|
||||
Image("ic_heart_pink")
|
||||
.resizable()
|
||||
.frame(width: 12, height: 12)
|
||||
|
||||
Text("\(totalHeart)")
|
||||
.font(.custom(Font.medium.rawValue, size: 12))
|
||||
.foregroundColor(.graybb)
|
||||
}
|
||||
.padding(.horizontal, 11)
|
||||
.padding(.vertical, 5.3)
|
||||
.overlay(
|
||||
RoundedRectangle(cornerRadius: 5.3)
|
||||
.stroke(Color.graybb, lineWidth: 1)
|
||||
)
|
||||
|
||||
HStack(spacing: 6.7) {
|
||||
Image("ic_can")
|
||||
.resizable()
|
||||
.frame(width: 12, height: 12)
|
||||
|
@ -217,6 +234,7 @@ struct LiveRoomInfoHostView_Previews: PreviewProvider {
|
|||
static var previews: some View {
|
||||
LiveRoomInfoHostView(
|
||||
title: "오늘의 라이브방송은 OOO입니다.",
|
||||
totalHeart: 1234,
|
||||
totalDonationCan: 123456,
|
||||
participantsCount: 18,
|
||||
isOnBg: true,
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
//
|
||||
// GetLiveRoomHeartTotalResponse.swift
|
||||
// SodaLive
|
||||
//
|
||||
// Created by klaus on 10/24/24.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct GetLiveRoomHeartTotalResponse: Decodable {
|
||||
let totalHeartCount: Int
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
//
|
||||
// LiveRoomLikeHeartRequest.swift
|
||||
// SodaLive
|
||||
//
|
||||
// Created by klaus on 10/24/24.
|
||||
//
|
||||
|
||||
struct LiveRoomLikeHeartRequest: Encodable {
|
||||
let roomId: Int
|
||||
let container: String = "ios"
|
||||
}
|
|
@ -25,6 +25,7 @@ struct LiveRoomViewV2: View {
|
|||
if liveRoomInfo.creatorId == UserDefaults.int(forKey: .userId) {
|
||||
LiveRoomInfoHostView(
|
||||
title: liveRoomInfo.title,
|
||||
totalHeart: viewModel.totalHeartCount,
|
||||
totalDonationCan: viewModel.totalDonationCan,
|
||||
participantsCount: liveRoomInfo.participantsCount,
|
||||
isOnBg: viewModel.isBgOn,
|
||||
|
@ -75,6 +76,7 @@ struct LiveRoomViewV2: View {
|
|||
} else {
|
||||
LiveRoomInfoGuestView(
|
||||
title: liveRoomInfo.title,
|
||||
totalHeart: viewModel.totalHeartCount,
|
||||
totalDonationCan: viewModel.totalDonationCan,
|
||||
isOnBg: viewModel.isBgOn,
|
||||
isOnNotice: viewModel.isShowNotice,
|
||||
|
|
Loading…
Reference in New Issue