|
|
|
|
@@ -4,12 +4,14 @@ import Moya
|
|
|
|
|
|
|
|
|
|
final class CreatorChannelReplyDetailViewModel: ObservableObject {
|
|
|
|
|
private let communityRepository = CreatorCommunityRepository()
|
|
|
|
|
private let v2CommunityRepository = CreatorChannelCommunityRepository()
|
|
|
|
|
private let explorerRepository = ExplorerRepository()
|
|
|
|
|
private let fanTalkRepository = CreatorChannelFanTalkRepository()
|
|
|
|
|
private var subscription = Set<AnyCancellable>()
|
|
|
|
|
private var context: CreatorChannelReplyDetailContext?
|
|
|
|
|
private var onFanTalkRefresh: (() -> Void)?
|
|
|
|
|
private var communityReplyPage = 1
|
|
|
|
|
private var onCommunityRefresh: (() -> Void)?
|
|
|
|
|
private var communityReplyPage = 0
|
|
|
|
|
private let communityReplyPageSize = 20
|
|
|
|
|
private var communityReplyTotalCount = 0
|
|
|
|
|
private var isCommunityReplyLast = false
|
|
|
|
|
@@ -35,16 +37,20 @@ final class CreatorChannelReplyDetailViewModel: ObservableObject {
|
|
|
|
|
editingItem != nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func configure(context: CreatorChannelReplyDetailContext, onFanTalkRefresh: (() -> Void)?) {
|
|
|
|
|
func configure(context: CreatorChannelReplyDetailContext, onFanTalkRefresh: (() -> Void)?, onCommunityRefresh: (() -> Void)? = nil) {
|
|
|
|
|
guard self.context == nil else { return }
|
|
|
|
|
|
|
|
|
|
self.context = context
|
|
|
|
|
self.onFanTalkRefresh = onFanTalkRefresh
|
|
|
|
|
self.onCommunityRefresh = onCommunityRefresh
|
|
|
|
|
|
|
|
|
|
switch context {
|
|
|
|
|
case .community(_, _, let parentComment):
|
|
|
|
|
parentItem = CreatorChannelReplyDetailDisplayItem(communityComment: parentComment)
|
|
|
|
|
fetchCommunityReplies(reset: true)
|
|
|
|
|
case .communityPostDetail(let creatorId, _, let parentComment):
|
|
|
|
|
parentItem = CreatorChannelReplyDetailDisplayItem(communityPostDetail: parentComment, creatorId: creatorId)
|
|
|
|
|
fetchCommunityReplies(reset: true)
|
|
|
|
|
case .fanTalk(let creatorId, let parentFanTalk):
|
|
|
|
|
parentItem = CreatorChannelReplyDetailDisplayItem(fanTalk: parentFanTalk)
|
|
|
|
|
replies = parentFanTalk.creatorReplies.map {
|
|
|
|
|
@@ -70,6 +76,9 @@ final class CreatorChannelReplyDetailViewModel: ObservableObject {
|
|
|
|
|
if case .community(let creatorId, _, _) = context {
|
|
|
|
|
return creatorId == UserDefaults.int(forKey: .userId)
|
|
|
|
|
}
|
|
|
|
|
if case .communityPostDetail(let creatorId, _, _) = context {
|
|
|
|
|
return creatorId == UserDefaults.int(forKey: .userId)
|
|
|
|
|
}
|
|
|
|
|
return false
|
|
|
|
|
case .fanTalk:
|
|
|
|
|
guard item.id > 0 else { return false }
|
|
|
|
|
@@ -127,11 +136,11 @@ final class CreatorChannelReplyDetailViewModel: ObservableObject {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func fetchCommunityReplies(reset: Bool = false) {
|
|
|
|
|
guard case .community(_, _, let parentComment) = context else { return }
|
|
|
|
|
guard isCommunityContext else { return }
|
|
|
|
|
guard isLoading == false, isLoadingNextPage == false else { return }
|
|
|
|
|
|
|
|
|
|
if reset {
|
|
|
|
|
communityReplyPage = 1
|
|
|
|
|
communityReplyPage = isCommunityPostDetailContext ? 0 : 1
|
|
|
|
|
communityReplyTotalCount = 0
|
|
|
|
|
isCommunityReplyLast = false
|
|
|
|
|
} else if isCommunityReplyLast {
|
|
|
|
|
@@ -145,7 +154,8 @@ final class CreatorChannelReplyDetailViewModel: ObservableObject {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let requestPage = communityReplyPage
|
|
|
|
|
communityRepository.getCommentReplyList(commentId: parentComment.id, page: requestPage, size: communityReplyPageSize)
|
|
|
|
|
let publisher = communityRepliesPublisher(page: requestPage)
|
|
|
|
|
publisher
|
|
|
|
|
.sink { [weak self] result in
|
|
|
|
|
guard let self else { return }
|
|
|
|
|
if case .failure(let error) = result {
|
|
|
|
|
@@ -157,27 +167,7 @@ final class CreatorChannelReplyDetailViewModel: ObservableObject {
|
|
|
|
|
self.isLoading = false
|
|
|
|
|
self.isLoadingNextPage = false
|
|
|
|
|
|
|
|
|
|
do {
|
|
|
|
|
let decoded = try JSONDecoder().decode(ApiResponse<GetCommunityPostCommentListResponse>.self, from: response.data)
|
|
|
|
|
if let data = decoded.data, decoded.success {
|
|
|
|
|
let newReplies = data.items.map { CreatorChannelReplyDetailDisplayItem(communityComment: $0) }
|
|
|
|
|
if reset || requestPage == 1 {
|
|
|
|
|
self.replies = newReplies
|
|
|
|
|
} else {
|
|
|
|
|
self.replies.append(contentsOf: newReplies)
|
|
|
|
|
}
|
|
|
|
|
self.communityReplyTotalCount = data.totalCount
|
|
|
|
|
self.communityReplyPage = requestPage + 1
|
|
|
|
|
self.isCommunityReplyLast = self.replies.count >= data.totalCount || newReplies.isEmpty
|
|
|
|
|
} else {
|
|
|
|
|
self.errorMessage = decoded.message ?? I18n.Common.commonError
|
|
|
|
|
self.isShowPopup = true
|
|
|
|
|
}
|
|
|
|
|
} catch {
|
|
|
|
|
ERROR_LOG(error.localizedDescription)
|
|
|
|
|
self.errorMessage = I18n.Common.commonError
|
|
|
|
|
self.isShowPopup = true
|
|
|
|
|
}
|
|
|
|
|
self.handleCommunityRepliesResponse(response, requestPage: requestPage, reset: reset)
|
|
|
|
|
}
|
|
|
|
|
.store(in: &subscription)
|
|
|
|
|
}
|
|
|
|
|
@@ -199,6 +189,24 @@ final class CreatorChannelReplyDetailViewModel: ObservableObject {
|
|
|
|
|
parentId: parentComment.id,
|
|
|
|
|
isSecret: parentComment.isSecret
|
|
|
|
|
)
|
|
|
|
|
.sink { [weak self] result in
|
|
|
|
|
guard let self else { return }
|
|
|
|
|
if case .failure(let error) = result {
|
|
|
|
|
ERROR_LOG(error.localizedDescription)
|
|
|
|
|
self.applyFailureState()
|
|
|
|
|
}
|
|
|
|
|
} receiveValue: { [weak self] response in
|
|
|
|
|
self?.handleCommunityMutationResponse(response)
|
|
|
|
|
}
|
|
|
|
|
.store(in: &subscription)
|
|
|
|
|
case .communityPostDetail(_, let postId, let parentComment):
|
|
|
|
|
isLoading = true
|
|
|
|
|
communityRepository.createCommunityPostComment(
|
|
|
|
|
comment: content,
|
|
|
|
|
postId: postId,
|
|
|
|
|
parentId: parentComment.commentId,
|
|
|
|
|
isSecret: false
|
|
|
|
|
)
|
|
|
|
|
.sink { [weak self] result in
|
|
|
|
|
guard let self else { return }
|
|
|
|
|
if case .failure(let error) = result {
|
|
|
|
|
@@ -350,6 +358,7 @@ final class CreatorChannelReplyDetailViewModel: ObservableObject {
|
|
|
|
|
let decoded = try JSONDecoder().decode(ApiResponseWithoutData.self, from: response.data)
|
|
|
|
|
if decoded.success {
|
|
|
|
|
applyLocalSuccessState()
|
|
|
|
|
onCommunityRefresh?()
|
|
|
|
|
fetchCommunityReplies(reset: true)
|
|
|
|
|
} else {
|
|
|
|
|
errorMessage = decoded.message ?? I18n.Common.commonError
|
|
|
|
|
@@ -410,7 +419,93 @@ final class CreatorChannelReplyDetailViewModel: ObservableObject {
|
|
|
|
|
|
|
|
|
|
private func applyFailureState() {
|
|
|
|
|
isLoading = false
|
|
|
|
|
isLoadingNextPage = false
|
|
|
|
|
errorMessage = I18n.Common.commonError
|
|
|
|
|
isShowPopup = true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private var isCommunityContext: Bool {
|
|
|
|
|
if case .community = context { return true }
|
|
|
|
|
if case .communityPostDetail = context { return true }
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private var isCommunityPostDetailContext: Bool {
|
|
|
|
|
if case .communityPostDetail = context { return true }
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private func communityRepliesPublisher(page: Int) -> AnyPublisher<Response, MoyaError> {
|
|
|
|
|
switch context {
|
|
|
|
|
case .community(_, _, let parentComment):
|
|
|
|
|
return communityRepository.getCommentReplyList(commentId: parentComment.id, page: page, size: communityReplyPageSize)
|
|
|
|
|
case .communityPostDetail(_, _, let parentComment):
|
|
|
|
|
return v2CommunityRepository.getCommunityCommentReplies(commentId: parentComment.commentId, page: page, size: communityReplyPageSize)
|
|
|
|
|
default:
|
|
|
|
|
return Fail(error: MoyaError.underlying(NSError(domain: "CreatorChannelReplyDetail", code: -1), nil)).eraseToAnyPublisher()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private func handleCommunityRepliesResponse(_ response: Moya.Response, requestPage: Int, reset: Bool) {
|
|
|
|
|
if isCommunityPostDetailContext {
|
|
|
|
|
handleCommunityPostDetailRepliesResponse(response, requestPage: requestPage, reset: reset)
|
|
|
|
|
} else {
|
|
|
|
|
handleLegacyCommunityRepliesResponse(response, requestPage: requestPage, reset: reset)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private func handleLegacyCommunityRepliesResponse(_ response: Moya.Response, requestPage: Int, reset: Bool) {
|
|
|
|
|
do {
|
|
|
|
|
let decoded = try JSONDecoder().decode(ApiResponse<GetCommunityPostCommentListResponse>.self, from: response.data)
|
|
|
|
|
if let data = decoded.data, decoded.success {
|
|
|
|
|
let newReplies = data.items.map { CreatorChannelReplyDetailDisplayItem(communityComment: $0) }
|
|
|
|
|
applyCommunityReplies(newReplies, requestPage: requestPage, reset: reset, totalCount: data.totalCount, hasNext: nil)
|
|
|
|
|
} else {
|
|
|
|
|
errorMessage = decoded.message ?? I18n.Common.commonError
|
|
|
|
|
isShowPopup = true
|
|
|
|
|
}
|
|
|
|
|
} catch {
|
|
|
|
|
ERROR_LOG(error.localizedDescription)
|
|
|
|
|
errorMessage = I18n.Common.commonError
|
|
|
|
|
isShowPopup = true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private func handleCommunityPostDetailRepliesResponse(_ response: Moya.Response, requestPage: Int, reset: Bool) {
|
|
|
|
|
do {
|
|
|
|
|
let decoded = try JSONDecoder().decode(ApiResponse<CreatorChannelCommunityRepliesResponse>.self, from: response.data)
|
|
|
|
|
if let data = decoded.data, decoded.success {
|
|
|
|
|
let creatorId = contextCreatorId
|
|
|
|
|
let newReplies = data.replies.map { CreatorChannelReplyDetailDisplayItem(communityPostDetailReply: $0, creatorId: creatorId) }
|
|
|
|
|
applyCommunityReplies(newReplies, requestPage: requestPage, reset: reset, totalCount: data.replyCount, hasNext: data.hasNext)
|
|
|
|
|
} else {
|
|
|
|
|
errorMessage = decoded.message ?? I18n.Common.commonError
|
|
|
|
|
isShowPopup = true
|
|
|
|
|
}
|
|
|
|
|
} catch {
|
|
|
|
|
ERROR_LOG(error.localizedDescription)
|
|
|
|
|
errorMessage = I18n.Common.commonError
|
|
|
|
|
isShowPopup = true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private var contextCreatorId: Int {
|
|
|
|
|
switch context {
|
|
|
|
|
case .community(let creatorId, _, _), .communityPostDetail(let creatorId, _, _), .fanTalk(let creatorId, _):
|
|
|
|
|
return creatorId
|
|
|
|
|
case .none:
|
|
|
|
|
return 0
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private func applyCommunityReplies(_ newReplies: [CreatorChannelReplyDetailDisplayItem], requestPage: Int, reset: Bool, totalCount: Int, hasNext: Bool?) {
|
|
|
|
|
if reset || requestPage == (isCommunityPostDetailContext ? 0 : 1) {
|
|
|
|
|
replies = newReplies
|
|
|
|
|
} else {
|
|
|
|
|
replies.append(contentsOf: newReplies)
|
|
|
|
|
}
|
|
|
|
|
communityReplyTotalCount = totalCount
|
|
|
|
|
communityReplyPage = requestPage + 1
|
|
|
|
|
isCommunityReplyLast = hasNext.map { !$0 } ?? (replies.count >= totalCount || newReplies.isEmpty)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|