// // UserProfileViewModel.swift // SodaLive // // Created by klaus on 2023/08/11. // import Foundation import Combine import FirebaseDynamicLinks 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 isExpandNotice = false @Published var paymentDialogTitle = "" @Published var paymentDialogDesc = "" @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 var isShowShareView = false @Published var shareMessage = "" @Published var isShowReportMenu = false @Published var isShowUesrBlockConfirm = false @Published var isShowUesrReportView = false @Published var isShowProfileReportConfirm = false @Published var reportCheersId = 0 @Published var isShowCheersReportMenu = false @Published var isShowCheersReportView = false let paymentDialogCancelTitle = "취소" 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 = "\(data.creator.nickname)님의 채널" } else { if let message = decoded.message { self.errorMessage = message } else { self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." } self.isShowPopup = true } } catch { self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." 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 = "내가 만든 라이브는 예약할 수 없습니다." 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 = "\($0.price)캔으로 예약" self.paymentDialogDesc = "'\($0.title)' 라이브에 참여하기 위해 결제합니다." self.paymentDialogConfirmTitle = "결제 후 예약하기" 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 = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." } self.isShowPopup = true } } catch { self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." 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 { self.paymentDialogTitle = "\($0.price)캔으로 입장" self.paymentDialogDesc = "'\($0.title)' 라이브에 참여하기 위해 결제합니다." self.paymentDialogConfirmTitle = "결제 후 참여하기" 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 = "라이브에 입장하지 못했습니다.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." } self.isShowPopup = true } } catch { self.errorMessage = "라이브에 입장하지 못했습니다.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." self.isShowPopup = true } } .store(in: &subscription) } func creatorFollow() { if let creator = creatorProfile { isLoading = true userRepository.creatorFollow(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 = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." } self.isShowPopup = true } } catch { self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." 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 = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." } self.isShowPopup = true } } catch { self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." 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 = "라이브 정보를 가져오지 못했습니다.\n다시 시도해 주세요." } self.isShowPopup = true } } catch { self.errorMessage = "라이브 정보를 가져오지 못했습니다.\n다시 시도해 주세요." self.isShowPopup = true } self.isLoading = false } .store(in: &subscription) } func shareChannel(userId: Int) { guard let link = URL(string: "https://sodalive.net/?channel_id=\(userId)") else { return } let dynamicLinksDomainURIPrefix = "https://sodalive.page.link" guard let linkBuilder = DynamicLinkComponents(link: link, domainURIPrefix: dynamicLinksDomainURIPrefix) else { self.errorMessage = "공유링크를 생성하지 못했습니다.\n다시 시도해 주세요." self.isShowPopup = true return } linkBuilder.iOSParameters = DynamicLinkIOSParameters(bundleID: "kr.co.vividnext.sodalive") linkBuilder.iOSParameters?.appStoreID = "6461721697" linkBuilder.androidParameters = DynamicLinkAndroidParameters(packageName: "kr.co.vividnext.sodalive") guard let longDynamicLink = linkBuilder.url else { self.errorMessage = "공유링크를 생성하지 못했습니다.\n다시 시도해 주세요." self.isShowPopup = true return } DEBUG_LOG("The long URL is: \(longDynamicLink)") DynamicLinkComponents.shortenURL(longDynamicLink, options: nil) { [unowned self] url, warnings, error in let shortUrl = url?.absoluteString let urlString = shortUrl != nil ? shortUrl! : longDynamicLink.absoluteString self.shareMessage = "소다라이브 \(self.creatorProfile!.creator.nickname)님의 채널입니다.\n\(urlString)" self.isShowShareView = true } } 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 = "차단하였습니다." } else { if let message = decoded.message { self.errorMessage = message } else { self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." } } self.isShowPopup = true } catch { self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." 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 = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." } } self.isShowPopup = true } catch { self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." 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: reportCheersId > 0 && type == .CHEERS ? reportCheersId : 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.reportCheersId = 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 = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." } self.isShowPopup = true } catch { self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." self.isShowPopup = true } } .store(in: &subscription) } }