// // UserProfileViewModel.swift // SodaLive // // Created by klaus on 2023/08/11. // import Foundation import Combine final class UserProfileViewModel: ObservableObject { private var repository = ExplorerRepository() private let liveRepository = LiveRepository() private let reportRepository = ReportRepository() private let userRepository = UserRepository() private var subscription = Set() @Published var errorMessage = "" @Published var isShowPopup = false @Published var isLoading = false @Published var paymentDialogTitle = "" @Published var paymentDialogDesc = "" @Published var paymentDialogDesc2 = "" @Published var isShowPaymentDialog = false @Published var paymentDialogConfirmAction = {} @Published var paymentDialogConfirmTitle = "" @Published var secretOrPasswordDialogCan = 0 @Published var passwordDialogConfirmAction: (String) -> Void = { _ in } @Published var isShowPasswordDialog = false @Published var navigationTitle = "채널" @Published private(set) var creatorProfile: GetCreatorProfileResponse? @Published private(set) var communityPostList = [GetCommunityPostListResponse]() @Published var isShowShareView = false @Published var shareMessage = "" @Published var isShowReportMenu = false @Published var isShowUesrBlockConfirm = false @Published var isShowUesrReportView = false @Published var isShowProfileReportConfirm = false @Published var cheersId = 0 @Published var isShowCheersReportView = false @Published var isShowCheersDeleteView = false @Published var liveStartDate: String? = nil @Published var nowDate: String? = nil let paymentDialogCancelTitle = I18n.Common.cancel func getCreatorProfile(userId: Int) { creatorProfile = nil isLoading = true repository.getCreatorProfile(id: userId) .sink { result in switch result { case .finished: DEBUG_LOG("finish") case .failure(let error): ERROR_LOG(error.localizedDescription) } } receiveValue: { [unowned self] response in let responseData = response.data do { let jsonDecoder = JSONDecoder() let decoded = try jsonDecoder.decode(ApiResponse.self, from: responseData) if let data = decoded.data, decoded.success { self.creatorProfile = data self.navigationTitle = I18n.MemberChannel.channelTitle(data.creator.nickname) self.communityPostList.removeAll() self.communityPostList.append(contentsOf: data.communityPostList) } else { if let message = decoded.message { self.errorMessage = message } else { self.errorMessage = I18n.Common.commonError } self.isShowPopup = true } } catch { self.errorMessage = I18n.Common.commonError self.isShowPopup = true } self.isLoading = false } .store(in: &subscription) } func hidePaymentPopup() { isShowPaymentDialog = false isShowPasswordDialog = false paymentDialogTitle = "" paymentDialogDesc = "" paymentDialogConfirmAction = {} secretOrPasswordDialogCan = 0 passwordDialogConfirmAction = { _ in } } func reservationLiveRoom(roomId: Int) { getRoomDetail(roomId: roomId) { [unowned self] in if ($0.manager.id == UserDefaults.int(forKey: .userId)) { self.errorMessage = I18n.MemberChannel.cannotReserveOwnLive self.isShowPopup = true } else { if $0.isPrivateRoom { self.passwordDialogConfirmAction = { password in self.reservation(roomId: roomId, password: password) } self.isShowPasswordDialog = true } else { if ($0.price == 0 || $0.isPaid) { self.reservation(roomId: roomId) } else { self.paymentDialogTitle = I18n.MemberChannel.reserveWithCansTitle($0.price) self.paymentDialogDesc = I18n.MemberChannel.reservePaymentDesc($0.title) self.paymentDialogConfirmTitle = I18n.MemberChannel.reservePaymentConfirmTitle self.paymentDialogConfirmAction = { [unowned self] in hidePaymentPopup() reservation(roomId: roomId) } self.isShowPaymentDialog = true } } } } } private func reservation(roomId: Int, password: String? = nil) { isLoading = true let request = MakeLiveReservationRequest(roomId: roomId, password: password) liveRepository.makeReservation(request: request) .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.self, from: responseData) if let response = decoded.data, decoded.success { AppState.shared.setAppStep(step: .liveReservationComplete(response: response)) } else { if let message = decoded.message { self.errorMessage = message } else { self.errorMessage = I18n.Common.commonError } self.isShowPopup = true } } catch { self.errorMessage = I18n.Common.commonError self.isShowPopup = true } } .store(in: &subscription) } func enterLiveRoom(roomId: Int) { getRoomDetail(roomId: roomId) { if let _ = $0.channelName { if $0.manager.id == UserDefaults.int(forKey: .userId) { DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.3) { self.enterRoom(roomId: roomId) } } else if ($0.price == 0 || $0.isPaid) { if $0.isPrivateRoom { self.passwordDialogConfirmAction = { password in self.enterRoom(roomId: roomId, password: password) } self.isShowPasswordDialog = true } else { DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.3) { self.enterRoom(roomId: roomId) } } } else { if $0.isPrivateRoom { self.secretOrPasswordDialogCan = $0.price self.passwordDialogConfirmAction = { password in self.enterRoom(roomId: roomId, password: password) } self.isShowPasswordDialog = true } else { if let beginDate = $0.beginDateTimeUtc.parseUtcIsoDate() { let now = Date() let timeInterval = now.timeIntervalSince(beginDate) let hours = Int(timeInterval / 3600) let minutes = Int((timeInterval.truncatingRemainder(dividingBy: 3600)) / 60) if hours >= 1 { self.liveStartDate = beginDate.convertDateFormat(dateFormat: "yyyy-MM-dd, HH:mm") self.nowDate = now.convertDateFormat(dateFormat: "yyyy-MM-dd, HH:mm") self.paymentDialogDesc2 = I18n.MemberChannel.elapsedLiveWarning(hours: hours, minutes: minutes) } } self.paymentDialogTitle = I18n.MemberChannel.paidLiveEnterTitle self.paymentDialogDesc = I18n.MemberChannel.paidLiveEnterDesc($0.price) self.paymentDialogConfirmTitle = I18n.MemberChannel.paidLiveConfirmTitle self.paymentDialogConfirmAction = { [unowned self] in hidePaymentPopup() self.enterRoom(roomId: roomId) } self.isShowPaymentDialog = true } } } } } func enterRoom(roomId: Int, onSuccess: (() -> Void)? = nil, password: String? = nil) { isLoading = true let request = EnterOrQuitLiveRoomRequest(roomId: roomId, password: password) liveRepository.enterRoom(request: request) .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(ApiResponseWithoutData.self, from: responseData) if decoded.success { AppState.shared.roomId = roomId if let onSuccess = onSuccess { onSuccess() } else { if roomId > 0 { AppState.shared.isShowPlayer = true AppState.shared.setAppStep(step: .main) } } } else { if let message = decoded.message { self.errorMessage = message } else { self.errorMessage = I18n.MemberChannel.enterLiveFailed } self.isShowPopup = true } } catch { self.errorMessage = I18n.MemberChannel.enterLiveFailed self.isShowPopup = true } } .store(in: &subscription) } func creatorFollow(follow: Bool = true, notify: Bool = true) { if let creator = creatorProfile { isLoading = true userRepository.creatorFollow(creatorId: creator.creator.creatorId, follow: follow, notify: notify) .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(ApiResponseWithoutData.self, from: responseData) if decoded.success { self.getCreatorProfile(userId: creator.creator.creatorId) } else { if let message = decoded.message { self.errorMessage = message } else { self.errorMessage = I18n.Common.commonError } self.isShowPopup = true } } catch { self.errorMessage = I18n.Common.commonError self.isShowPopup = true } } .store(in: &subscription) } } func creatorUnFollow() { if let creator = creatorProfile { isLoading = true userRepository.creatorUnFollow(creatorId: creator.creator.creatorId) .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(ApiResponseWithoutData.self, from: responseData) if decoded.success { self.getCreatorProfile(userId: creator.creator.creatorId) } else { if let message = decoded.message { self.errorMessage = message } else { self.errorMessage = I18n.Common.commonError } self.isShowPopup = true } } catch { self.errorMessage = I18n.Common.commonError self.isShowPopup = true } } .store(in: &subscription) } } private func getRoomDetail(roomId: Int, onSuccess: @escaping (GetRoomDetailResponse) -> Void) { isLoading = true liveRepository.getRoomDetail(roomId: roomId) .sink { result in switch result { case .finished: DEBUG_LOG("finish") case .failure(let error): ERROR_LOG(error.localizedDescription) } } receiveValue: { response in let responseData = response.data do { let jsonDecoder = JSONDecoder() let decoded = try jsonDecoder.decode(ApiResponse.self, from: responseData) if let data = decoded.data, decoded.success { onSuccess(data) } else { if let message = decoded.message { self.errorMessage = message } else { self.errorMessage = I18n.MemberChannel.fetchLiveInfoFailed } self.isShowPopup = true } } catch { self.errorMessage = I18n.MemberChannel.fetchLiveInfoFailed self.isShowPopup = true } self.isLoading = false } .store(in: &subscription) } func shareChannel(userId: Int, nickname: String, profileImage: String) { isLoading = true let params = [ "af_dp": "voiceon://", "deep_link_value": "channel", "deep_link_sub5": "\(userId)" ] if let shareUrl = createOneLinkUrlWithURLComponents(params: params) { self.shareMessage = I18n.MemberChannel.shareChannelMessage(nickname) + "\n\(shareUrl)" self.isShowShareView = true } else { self.errorMessage = I18n.MemberChannel.shareLinkCreateFailed self.isShowPopup = true } self.isLoading = false } func userBlock(userId: Int) { isLoading = true userRepository.memberBlock(userId: userId) .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(ApiResponseWithoutData.self, from: responseData) if decoded.success { getCreatorProfile(userId: userId) self.errorMessage = I18n.MemberChannel.userBlocked } else { if let message = decoded.message { self.errorMessage = message } else { self.errorMessage = I18n.Common.commonError } } self.isShowPopup = true } catch { self.errorMessage = I18n.Common.commonError self.isShowPopup = true } } .store(in: &subscription) } func userUnBlock(userId: Int) { isLoading = true userRepository.memberUnBlock(userId: userId) .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(ApiResponseWithoutData.self, from: responseData) if decoded.success { getCreatorProfile(userId: userId) self.errorMessage = "차단이 해제 되었습니다." } else { if let message = decoded.message { self.errorMessage = message } else { self.errorMessage = I18n.Common.commonError } } self.isShowPopup = true } catch { self.errorMessage = I18n.Common.commonError self.isShowPopup = true } } .store(in: &subscription) } func report(type: ReportType, userId: Int? = nil, reason: String = "프로필 신고") { isLoading = true let request = ReportRequest(type: type, reason: reason, reportedMemberId: userId, cheersId: cheersId > 0 && type == .CHEERS ? cheersId : nil, audioContentId: nil) reportRepository.report(request: request) .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 self.cheersId = 0 do { let jsonDecoder = JSONDecoder() let decoded = try jsonDecoder.decode(ApiResponseWithoutData.self, from: responseData) if let message = decoded.message { self.errorMessage = message } else { self.errorMessage = I18n.Common.commonError } self.isShowPopup = true } catch { self.errorMessage = I18n.Common.commonError self.isShowPopup = true } } .store(in: &subscription) } func deleteCheers(creatorId: Int) { isLoading = true repository.modifyCheers(cheersId: cheersId, content: nil, isActive: false) .sink { result in switch result { case .finished: DEBUG_LOG("finish") case .failure(let error): ERROR_LOG(error.localizedDescription) } } receiveValue: { [unowned self] response in self.cheersId = 0 self.isLoading = false let responseData = response.data do { let jsonDecoder = JSONDecoder() let decoded = try jsonDecoder.decode(ApiResponseWithoutData.self, from: responseData) if decoded.success { self.getCreatorProfile(userId: creatorId) } else { if let message = decoded.message { self.errorMessage = message } else { self.errorMessage = I18n.Common.commonError } self.isShowPopup = true } } catch { self.errorMessage = I18n.Common.commonError self.isShowPopup = true } } .store(in: &subscription) } }