feat(creator): 팬Talk 탭을 추가한다
This commit is contained in:
@@ -0,0 +1,159 @@
|
||||
import SwiftUI
|
||||
|
||||
struct CreatorChannelFanTalkTabView: View {
|
||||
let creatorId: Int
|
||||
let isOwnCreatorChannel: Bool
|
||||
@ObservedObject var viewModel: CreatorChannelFanTalkViewModel
|
||||
let onTapWrite: () -> Void
|
||||
|
||||
@State private var actionPopupFanTalk: CreatorChannelFanTalkItemResponse?
|
||||
@State private var fanTalkItemFrames = [Int: CGRect]()
|
||||
|
||||
var body: some View {
|
||||
ZStack(alignment: .topTrailing) {
|
||||
content
|
||||
|
||||
actionPopupLayer
|
||||
.zIndex(1)
|
||||
}
|
||||
.coordinateSpace(name: Self.coordinateSpaceName)
|
||||
.background(Color.black)
|
||||
.onPreferenceChange(CreatorChannelFanTalkItemFramePreferenceKey.self) { frames in
|
||||
fanTalkItemFrames.merge(frames) { _, new in new }
|
||||
}
|
||||
.onAppear {
|
||||
if viewModel.hasLoaded == false {
|
||||
viewModel.fetchFirstPage(creatorId: creatorId)
|
||||
}
|
||||
}
|
||||
.sodaToast(isPresented: $viewModel.isShowPopup, message: viewModel.errorMessage, autohideIn: 1)
|
||||
.overlay(reportDialog)
|
||||
.overlay(deleteDialog)
|
||||
}
|
||||
|
||||
private var content: some View {
|
||||
VStack(spacing: 0) {
|
||||
CreatorChannelFanTalkCountBar(fanTalkCount: viewModel.fanTalkCount)
|
||||
|
||||
if isEmptyState {
|
||||
CreatorChannelFanTalkEmptyView(
|
||||
showsWriteButton: isOwnCreatorChannel == false,
|
||||
onTapWrite: onTapWrite
|
||||
)
|
||||
} else {
|
||||
LazyVStack(spacing: 0) {
|
||||
ForEach(viewModel.fanTalks) { fanTalk in
|
||||
fanTalkItem(fanTalk)
|
||||
.onAppear {
|
||||
viewModel.fetchNextPageIfNeeded(
|
||||
creatorId: creatorId,
|
||||
currentItem: fanTalk
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if viewModel.isLoadingNextPage {
|
||||
ProgressView()
|
||||
.padding(.vertical, SodaSpacing.s20)
|
||||
}
|
||||
}
|
||||
.padding(.bottom, SodaSpacing.s20)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func fanTalkItem(_ fanTalk: CreatorChannelFanTalkItemResponse) -> some View {
|
||||
let isMine = fanTalk.writerId == UserDefaults.int(forKey: .userId)
|
||||
|
||||
return CreatorChannelFanTalkListItem(
|
||||
fanTalk: fanTalk,
|
||||
isMine: isMine,
|
||||
isOwnCreatorChannel: isOwnCreatorChannel,
|
||||
onTapReport: {
|
||||
actionPopupFanTalk = nil
|
||||
viewModel.presentReportDialog(fanTalkId: fanTalk.fanTalkId)
|
||||
},
|
||||
onTapMore: {
|
||||
actionPopupFanTalk = actionPopupFanTalk?.fanTalkId == fanTalk.fanTalkId ? nil : fanTalk
|
||||
}
|
||||
)
|
||||
.background {
|
||||
GeometryReader { proxy in
|
||||
Color.clear.preference(
|
||||
key: CreatorChannelFanTalkItemFramePreferenceKey.self,
|
||||
value: [fanTalk.fanTalkId: proxy.frame(in: .named(Self.coordinateSpaceName))]
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private var actionPopupLayer: some View {
|
||||
if let fanTalk = actionPopupFanTalk,
|
||||
let itemFrame = fanTalkItemFrames[fanTalk.fanTalkId] {
|
||||
let isMine = fanTalk.writerId == UserDefaults.int(forKey: .userId)
|
||||
|
||||
CreatorChannelFanTalkActionPopup(
|
||||
isMine: isMine,
|
||||
isOwnCreatorChannel: isOwnCreatorChannel,
|
||||
onTapEdit: {
|
||||
actionPopupFanTalk = nil
|
||||
},
|
||||
onTapDelete: {
|
||||
actionPopupFanTalk = nil
|
||||
viewModel.presentDeleteDialog(fanTalkId: fanTalk.fanTalkId)
|
||||
}
|
||||
)
|
||||
.padding(.top, itemFrame.minY + 44)
|
||||
.padding(.trailing, SodaSpacing.s14)
|
||||
}
|
||||
}
|
||||
|
||||
private var isEmptyState: Bool {
|
||||
guard viewModel.hasLoaded else { return false }
|
||||
return viewModel.fanTalkCount == 0
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private var reportDialog: some View {
|
||||
if viewModel.isShowReportDialog {
|
||||
CheersReportDialogView(
|
||||
isShowing: $viewModel.isShowReportDialog,
|
||||
confirmAction: { reason in
|
||||
viewModel.report(reason: reason)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private var deleteDialog: some View {
|
||||
if viewModel.isShowDeleteDialog {
|
||||
SodaDialog(
|
||||
title: I18n.MemberChannel.cheersDeleteTitle,
|
||||
desc: I18n.Common.confirmDeleteQuestion,
|
||||
confirmButtonTitle: I18n.Common.delete,
|
||||
confirmButtonAction: {
|
||||
viewModel.isShowDeleteDialog = false
|
||||
viewModel.deleteSelectedFanTalk(creatorId: creatorId)
|
||||
},
|
||||
cancelButtonTitle: I18n.Common.cancel,
|
||||
cancelButtonAction: {
|
||||
viewModel.isShowDeleteDialog = false
|
||||
viewModel.selectedFanTalkId = 0
|
||||
},
|
||||
textAlignment: .center
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private static let coordinateSpaceName = "CreatorChannelFanTalkTabView"
|
||||
}
|
||||
|
||||
private struct CreatorChannelFanTalkItemFramePreferenceKey: PreferenceKey {
|
||||
static var defaultValue: [Int: CGRect] = [:]
|
||||
|
||||
static func reduce(value: inout [Int: CGRect], nextValue: () -> [Int: CGRect]) {
|
||||
value.merge(nextValue()) { _, new in new }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user