feat(creator): 본인 채널 액션 기반을 추가한다

This commit is contained in:
Yu Sung
2026-07-03 21:05:40 +09:00
parent ca5432532e
commit 5059cd4a40
7 changed files with 755 additions and 191 deletions

View File

@@ -3178,6 +3178,10 @@ If you block this user, the following features will be restricted.
static var follow: String { pick(ko: "팔로우", en: "Follow", ja: "フォロー") }
static var following: String { pick(ko: "팔로잉", en: "Following", ja: "フォロー中") }
static var talk: String { pick(ko: "대화하기", en: "Start chat", ja: "会話する") }
static var uploadCommunityPost: String { pick(ko: "커뮤니티 글 올리기", en: "Upload community post", ja: "コミュニティ投稿を作成") }
static var uploadAudioContent: String { pick(ko: "오디오 콘텐츠 올리기", en: "Upload audio content", ja: "オーディオコンテンツを投稿") }
static var createLive: String { pick(ko: "라이브 만들기", en: "Create live", ja: "ライブを作成") }
static var closeFloatingMenu: String { pick(ko: "닫기", en: "Close", ja: "閉じる") }
static var viewAll: String { pick(ko: "전체보기", en: "View all", ja: "すべて見る") }
static var debut: String { pick(ko: "데뷔", en: "Debut", ja: "デビュー") }
static var liveCount: String { pick(ko: "라이브 총 진행 수", en: "Total live count", ja: "ライブ総配信数") }

View File

@@ -0,0 +1,106 @@
import SwiftUI
struct CreatorChannelFloatingActionMenu: View {
@Binding var isPresented: Bool
let onTapCommunityPost: () -> Void
let onTapAudioContent: () -> Void
let onTapCreateLive: () -> Void
private let buttonSize: CGFloat = 66
private let animation = Animation.interpolatingSpring(mass: 1, stiffness: 256, damping: 24, initialVelocity: 0)
var body: some View {
ZStack(alignment: .bottomTrailing) {
if isPresented {
Color.black
.opacity(0.4)
.ignoresSafeArea()
.onTapGesture {
withAnimation(animation) {
isPresented = false
}
}
}
VStack(spacing: SodaSpacing.s14) {
if isPresented {
floatingButton(
imageName: "ic_new_upload_community_post",
backgroundColor: Color.soda400,
accessibilityLabel: I18n.CreatorChannelHome.uploadCommunityPost,
action: onTapCommunityPost
)
floatingButton(
imageName: "ic_new_upload_audio",
backgroundColor: Color.soda400,
accessibilityLabel: I18n.CreatorChannelHome.uploadAudioContent,
action: onTapAudioContent
)
floatingButton(
imageName: "ic_new_create_live",
backgroundColor: Color.soda800,
accessibilityLabel: I18n.CreatorChannelHome.createLive,
action: onTapCreateLive
)
floatingButton(
imageName: "ic_new_x_black",
backgroundColor: Color.white,
accessibilityLabel: I18n.CreatorChannelHome.closeFloatingMenu
) {
withAnimation(animation) {
isPresented = false
}
}
} else {
floatingButton(
imageName: "ic_plus_no_bg",
backgroundColor: Color.soda400,
accessibilityLabel: "FAB"
) {
withAnimation(animation) {
isPresented = true
}
}
}
}
.padding(.trailing, SodaSpacing.s20)
.padding(.bottom, SodaSpacing.s32)
.animation(animation, value: isPresented)
}
}
private func floatingButton(
imageName: String,
backgroundColor: Color,
accessibilityLabel: String,
action: @escaping () -> Void
) -> some View {
Button(action: action) {
Image(imageName)
.resizable()
.frame(width: 38, height: 38)
.frame(width: buttonSize, height: buttonSize)
.background(backgroundColor)
.clipShape(Circle())
}
.accessibilityLabel(accessibilityLabel)
.buttonStyle(.plain)
}
}
struct CreatorChannelFloatingActionMenu_Previews: PreviewProvider {
static var previews: some View {
ZStack {
Color.black.ignoresSafeArea()
CreatorChannelFloatingActionMenu(
isPresented: .constant(false),
onTapCommunityPost: {},
onTapAudioContent: {},
onTapCreateLive: {}
)
}
}
}

View File

@@ -5,6 +5,7 @@ struct CreatorChannelTitleBar: View {
let isFollow: Bool
let isNotify: Bool
let backgroundProgress: CGFloat
let showsCreatorActions: Bool
let onTapBack: () -> Void
let onTapFollow: () -> Void
let onTapUnfollow: () -> Void
@@ -12,6 +13,32 @@ struct CreatorChannelTitleBar: View {
let onTapUnnotify: () -> Void
let onTapMore: () -> Void
init(
nickname: String,
isFollow: Bool,
isNotify: Bool,
backgroundProgress: CGFloat,
showsCreatorActions: Bool = true,
onTapBack: @escaping () -> Void,
onTapFollow: @escaping () -> Void,
onTapUnfollow: @escaping () -> Void,
onTapNotify: @escaping () -> Void,
onTapUnnotify: @escaping () -> Void,
onTapMore: @escaping () -> Void
) {
self.nickname = nickname
self.isFollow = isFollow
self.isNotify = isNotify
self.backgroundProgress = backgroundProgress
self.showsCreatorActions = showsCreatorActions
self.onTapBack = onTapBack
self.onTapFollow = onTapFollow
self.onTapUnfollow = onTapUnfollow
self.onTapNotify = onTapNotify
self.onTapUnnotify = onTapUnnotify
self.onTapMore = onTapMore
}
var body: some View {
HStack(spacing: SodaSpacing.s12) {
Button(action: onTapBack) {
@@ -29,21 +56,23 @@ struct CreatorChannelTitleBar: View {
.opacity(backgroundProgress >= 1 ? 1 : 0)
.frame(maxWidth: .infinity, alignment: .leading)
HStack(spacing: SodaSpacing.s14) {
followButton
if showsCreatorActions {
HStack(spacing: SodaSpacing.s14) {
followButton
if isFollow {
notifyButton
}
if isFollow {
notifyButton
}
Button(action: onTapMore) {
Image("ic_new_more")
.resizable()
.frame(width: 24, height: 24)
Button(action: onTapMore) {
Image("ic_new_more")
.resizable()
.frame(width: 24, height: 24)
}
.buttonStyle(.plain)
}
.buttonStyle(.plain)
.layoutPriority(1)
}
.layoutPriority(1)
}
.padding(.horizontal, SodaSpacing.s14)
.frame(height: 56)
@@ -93,6 +122,7 @@ struct CreatorChannelTitleBar_Previews: PreviewProvider {
isFollow: false,
isNotify: false,
backgroundProgress: 1,
showsCreatorActions: true,
onTapBack: {},
onTapFollow: {},
onTapUnfollow: {},
@@ -106,6 +136,7 @@ struct CreatorChannelTitleBar_Previews: PreviewProvider {
isFollow: true,
isNotify: true,
backgroundProgress: 1,
showsCreatorActions: true,
onTapBack: {},
onTapFollow: {},
onTapUnfollow: {},
@@ -119,6 +150,21 @@ struct CreatorChannelTitleBar_Previews: PreviewProvider {
isFollow: true,
isNotify: false,
backgroundProgress: 1,
showsCreatorActions: true,
onTapBack: {},
onTapFollow: {},
onTapUnfollow: {},
onTapNotify: {},
onTapUnnotify: {},
onTapMore: {}
)
CreatorChannelTitleBar(
nickname: "Soda Creator",
isFollow: true,
isNotify: true,
backgroundProgress: 1,
showsCreatorActions: false,
onTapBack: {},
onTapFollow: {},
onTapUnfollow: {},

View File

@@ -20,6 +20,13 @@ struct CreatorChannelView: View {
private let titleBarHeight: CGFloat = 56
private let tabBarHeight: CGFloat = 52
private var isOwnCreatorChannel: Bool {
guard let creatorId = viewModel.response?.creator.creatorId else { return false }
let userId = UserDefaults.int(forKey: .userId)
guard userId > 0 else { return false }
return creatorId == userId
}
init(creatorId: Int, viewModel: CreatorChannelViewModel = CreatorChannelViewModel()) {
self.creatorId = creatorId
@@ -124,6 +131,7 @@ struct CreatorChannelView: View {
isFollow: viewModel.response?.creator.isFollow ?? false,
isNotify: viewModel.response?.creator.isNotify ?? false,
backgroundProgress: backgroundProgress,
showsCreatorActions: !isOwnCreatorChannel,
onTapBack: {
dismiss()
},