From efd4da6a9dc316a1aa12c9da67f1958185fa30ec Mon Sep 17 00:00:00 2001 From: Yu Sung Date: Fri, 17 Oct 2025 09:53:04 +0900 Subject: [PATCH] =?UTF-8?q?feat(creator-channel):=20=EB=8B=89=EB=84=A4?= =?UTF-8?q?=EC=9E=84,=20=ED=8C=94=EB=A1=9C=EC=9B=8C=20=ED=91=9C=EC=8B=9C?= =?UTF-8?q?=20UI=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Explorer/Profile/UserProfileView.swift | 571 ++++++++++-------- 1 file changed, 307 insertions(+), 264 deletions(-) diff --git a/SodaLive/Sources/Explorer/Profile/UserProfileView.swift b/SodaLive/Sources/Explorer/Profile/UserProfileView.swift index 21b4367..3ac8585 100644 --- a/SodaLive/Sources/Explorer/Profile/UserProfileView.swift +++ b/SodaLive/Sources/Explorer/Profile/UserProfileView.swift @@ -27,290 +27,333 @@ struct UserProfileView: View { GeometryReader { proxy in BaseView(isLoading: $viewModel.isLoading) { ZStack(alignment: .top) { - VStack(spacing: 0) { - ScrollView(.vertical, showsIndicators: false) { - LazyVStack(spacing: 48) { - if let creatorProfile = viewModel.creatorProfile { - ZStack(alignment: .bottomLeading) { - KFImage(URL(string: creatorProfile.creator.profileUrl)) - .cancelOnDisappear(true) - .downsampling(size: CGSize(width: screenSize().width, height: screenSize().width)) - .resizable() - .aspectRatio(1, contentMode: .fill) - .frame(maxWidth: screenSize().width) - .clipped() - } + ScrollView(.vertical, showsIndicators: false) { + LazyVStack(spacing: 48) { + if let creatorProfile = viewModel.creatorProfile { + ZStack(alignment: .bottomLeading) { + KFImage(URL(string: creatorProfile.creator.profileUrl)) + .cancelOnDisappear(true) + .downsampling(size: CGSize(width: screenSize().width, height: screenSize().width)) + .resizable() + .aspectRatio(1, contentMode: .fill) + .frame(maxWidth: screenSize().width) + .clipped() - if let item = creatorProfile.latestContent { - HStack(spacing: 16) { - KFImage(URL(string: item.coverImageUrl)) - .cancelOnDisappear(true) - .downsampling(size: CGSize(width: 133, height: 133)) - .resizable() - .scaledToFill() - .frame(width: 133, height: 133, alignment: .top) - .clipped() - .cornerRadius(12) + VStack(alignment: .leading, spacing: 8) { + HStack(spacing: 8) { + Text(creatorProfile.creator.nickname) + .font(.custom(Font.preBold.rawValue, size: 32)) + .foregroundColor(.white) - VStack(alignment: .leading, spacing: 8) { - Text("최신 콘텐츠") - .font(.custom(Font.preMedium.rawValue, size: 12)) - .foregroundColor(.button) - .padding(.horizontal, 7) - .padding(.vertical, 4) - .background(Color(hex: "263238")) - .cornerRadius(4) - .overlay { - RoundedRectangle(cornerRadius: 4) - .strokeBorder(lineWidth: 1) - .foregroundColor(.button) - } - - HStack(spacing: 8) { - if item.isScheduledToOpen { - Text("오픈예정") - .font(.custom(Font.preMedium.rawValue, size: 12)) - .foregroundColor(Color(hex: "3bb9f1")) - .padding(2.6) - .background(Color(hex: "003851")) - .cornerRadius(2.6) - } - - Text(item.themeStr) - .font(.custom(Font.preMedium.rawValue, size: 12)) - .foregroundColor(Color(hex: "3bac6a")) - .padding(2.6) - .background(Color(hex: "28312b")) - .cornerRadius(2.6) - - Text(item.duration!) - .font(.custom(Font.preMedium.rawValue, size: 12)) - .foregroundColor(Color(hex: "777777")) - .padding(2.6) - .background(Color(hex: "222222")) - .cornerRadius(2.6) - - if item.isPointAvailable { - Text("포인트") - .font(.custom(Font.preMedium.rawValue, size: 12)) - .foregroundColor(.white) - .padding(2.6) - .background(Color(hex: "7849bc")) - .cornerRadius(2.6) - } - } - - Text(item.title) - .font(.custom(Font.preMedium.rawValue, size: 18)) - .foregroundColor(Color.white) - .multilineTextAlignment(.leading) - - HStack(spacing: 14) { - HStack(spacing: 6) { - Image("ic_heart_777") - .resizable() - .frame(width: 24, height: 24) - - Text("\(item.likeCount)") - .font(.custom(Font.preMedium.rawValue, size: 18)) - .foregroundColor(Color(hex: "777777")) - } - - HStack(spacing: 6) { - Image("ic_message_square_777") - .resizable() - .frame(width: 24, height: 24) - - Text("\(item.commentCount)") - .font(.custom(Font.preMedium.rawValue, size: 18)) - .foregroundColor(Color(hex: "777777")) - } - } - } - - Spacer() - } - .frame(maxWidth: .infinity) - .frame(alignment: .leading) - .padding(.horizontal, 24) - .onTapGesture { - AppState.shared - .setAppStep(step: .contentDetail(contentId: item.contentId)) - } - } - - if creatorProfile.creator.creatorId == UserDefaults.int(forKey: .userId) || creatorProfile.liveRoomList.count > 0 { - VStack(alignment: .leading, spacing: 14) { - HStack(spacing: 0) { - Text("라이브") - .font(.custom(Font.preBold.rawValue, size: 26)) - .foregroundColor(Color.white) - - Spacer() - } - - if creatorProfile.creator.creatorId == UserDefaults.int(forKey: .userId) { - HStack(spacing: 8) { - Text("룰렛 설정") - .font(.custom(Font.preBold.rawValue, size: 16)) - .foregroundColor(Color.grayee) - .padding(.vertical, 12) - .frame(maxWidth: .infinity) - .background(Color.button) - .cornerRadius(12) - .onTapGesture { isShowRouletteSettings = true } - - Text("메뉴 설정") - .font(.custom(Font.preBold.rawValue, size: 16)) - .foregroundColor(Color.grayee) - .padding(.vertical, 12) - .frame(maxWidth: .infinity) - .background(Color.button) - .cornerRadius(12) - .onTapGesture { isShowMenuSettings = true } - } - } - - if creatorProfile.liveRoomList.count > 0 { - UserProfileLiveView( - userId: userId, - liveRoomList: creatorProfile.liveRoomList, - onClickParticipant: { liveRoom in - if creatorProfile.creator.creatorId == UserDefaults.int(forKey: .userId) { - viewModel.errorMessage = "현재 라이브 중입니다." - viewModel.isShowPopup = true - } else { - AppState.shared.isShowPlayer = false - DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { - viewModel.enterLiveRoom(roomId: liveRoom.roomId) - } - } - }, - onClickReservation: { liveRoom in - if creatorProfile.creator.creatorId == UserDefaults.int(forKey: .userId) { - viewModel.errorMessage = "내가 만든 라이브는 예약할 수 없습니다." - viewModel.isShowPopup = true - } else { - viewModel.reservationLiveRoom(roomId: liveRoom.roomId) - } - } + if creatorProfile.creator.creatorId != UserDefaults.int(forKey: .userId) { + Image( + creatorProfile.creator.isFollow ? + creatorProfile.creator.isNotify ? "btn_following_big": "btn_following_no_alarm_big" + : "btn_follow_big" ) + .resizable() + .frame(width: 83.3, height: 26.7) + .onTapGesture { + if creatorProfile.creator.isFollow { + isShowFollowNotifyDialog = true + } else { + viewModel.creatorFollow() + } + } + } + } + + if creatorProfile.creator.creatorId == UserDefaults.int(forKey: .userId) { + Text("팔로워 리스트") + .font(.custom(Font.preBold.rawValue, size: 16)) + .foregroundColor(Color.black) + .padding(.vertical, 8) + .frame(maxWidth: .infinity) + .background(Color.white) + .cornerRadius(999) + .onTapGesture { + AppState.shared.setAppStep(step: .followerList(userId: creatorProfile.creator.creatorId)) + } + } else { + VStack(alignment: .leading, spacing: 9.3) { + Text("팔로워 \(creatorProfile.creator.notificationRecipientCount)명") + .font(.custom(Font.preMedium.rawValue, size: 16)) + .foregroundColor(Color.white) } } - .padding(.horizontal, 24) } - - if creatorProfile.creator.creatorId == UserDefaults.int(forKey: .userId) || creatorProfile.contentList.count > 0 { - UserProfileContentView( - userId: userId, - items: creatorProfile.contentList, - totalContentCount: creatorProfile.totalContentCount, - ownedContentCount: creatorProfile.ownedContentCount - ) - .padding(.horizontal, 24) + .padding(24) + } + + if let item = creatorProfile.latestContent { + HStack(spacing: 16) { + KFImage(URL(string: item.coverImageUrl)) + .cancelOnDisappear(true) + .downsampling(size: CGSize(width: 133, height: 133)) + .resizable() + .scaledToFill() + .frame(width: 133, height: 133, alignment: .top) + .clipped() + .cornerRadius(12) + + VStack(alignment: .leading, spacing: 8) { + Text("최신 콘텐츠") + .font(.custom(Font.preMedium.rawValue, size: 12)) + .foregroundColor(.button) + .padding(.horizontal, 7) + .padding(.vertical, 4) + .background(Color(hex: "263238")) + .cornerRadius(4) + .overlay { + RoundedRectangle(cornerRadius: 4) + .strokeBorder(lineWidth: 1) + .foregroundColor(.button) + } + + HStack(spacing: 8) { + if item.isScheduledToOpen { + Text("오픈예정") + .font(.custom(Font.preMedium.rawValue, size: 12)) + .foregroundColor(Color(hex: "3bb9f1")) + .padding(2.6) + .background(Color(hex: "003851")) + .cornerRadius(2.6) + } + + Text(item.themeStr) + .font(.custom(Font.preMedium.rawValue, size: 12)) + .foregroundColor(Color(hex: "3bac6a")) + .padding(2.6) + .background(Color(hex: "28312b")) + .cornerRadius(2.6) + + Text(item.duration!) + .font(.custom(Font.preMedium.rawValue, size: 12)) + .foregroundColor(Color(hex: "777777")) + .padding(2.6) + .background(Color(hex: "222222")) + .cornerRadius(2.6) + + if item.isPointAvailable { + Text("포인트") + .font(.custom(Font.preMedium.rawValue, size: 12)) + .foregroundColor(.white) + .padding(2.6) + .background(Color(hex: "7849bc")) + .cornerRadius(2.6) + } + } + + Text(item.title) + .font(.custom(Font.preMedium.rawValue, size: 18)) + .foregroundColor(Color.white) + .multilineTextAlignment(.leading) + + HStack(spacing: 14) { + HStack(spacing: 6) { + Image("ic_heart_777") + .resizable() + .frame(width: 24, height: 24) + + Text("\(item.likeCount)") + .font(.custom(Font.preMedium.rawValue, size: 18)) + .foregroundColor(Color(hex: "777777")) + } + + HStack(spacing: 6) { + Image("ic_message_square_777") + .resizable() + .frame(width: 24, height: 24) + + Text("\(item.commentCount)") + .font(.custom(Font.preMedium.rawValue, size: 18)) + .foregroundColor(Color(hex: "777777")) + } + } + } + + Spacer() } - + .frame(maxWidth: .infinity) + .frame(alignment: .leading) + .padding(.horizontal, 24) + .onTapGesture { + AppState.shared + .setAppStep(step: .contentDetail(contentId: item.contentId)) + } + } + + if creatorProfile.creator.creatorId == UserDefaults.int(forKey: .userId) || creatorProfile.liveRoomList.count > 0 { VStack(alignment: .leading, spacing: 14) { HStack(spacing: 0) { - Text("커뮤니티") + Text("라이브") .font(.custom(Font.preBold.rawValue, size: 26)) .foregroundColor(Color.white) - .padding(.horizontal, 24) Spacer() } - if viewModel.communityPostList.count > 0 { - ScrollView(.horizontal, showsIndicators: false) { - LazyHStack(spacing: 14) { - if UserDefaults.int(forKey: .userId) == creatorProfile.creator.creatorId { - CreatorCommunityWriteItemView() - .onTapGesture { - AppState.shared.setAppStep( - step: .creatorCommunityWrite( - onSuccess: creatorCommunityWriteSuccess - ) - ) - } - } - - ForEach(0.. 0 { + UserProfileLiveView( + userId: userId, + liveRoomList: creatorProfile.liveRoomList, + onClickParticipant: { liveRoom in + if creatorProfile.creator.creatorId == UserDefaults.int(forKey: .userId) { + viewModel.errorMessage = "현재 라이브 중입니다." + viewModel.isShowPopup = true + } else { + AppState.shared.isShowPlayer = false + DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { + viewModel.enterLiveRoom(roomId: liveRoom.roomId) + } + } + }, + onClickReservation: { liveRoom in + if creatorProfile.creator.creatorId == UserDefaults.int(forKey: .userId) { + viewModel.errorMessage = "내가 만든 라이브는 예약할 수 없습니다." + viewModel.isShowPopup = true + } else { + viewModel.reservationLiveRoom(roomId: liveRoom.roomId) + } + } + ) + } } - - if !creatorProfile.seriesList.isEmpty { - UserProfileSeriesView( - creatorId: creatorProfile.creator.creatorId, - items: creatorProfile.seriesList - ) - } - - if creatorProfile.userDonationRanking.count > 0 { - UserProfileDonationView(userId: userId, donationRankingResponse: creatorProfile.userDonationRanking) - } - - UserProfileFanTalkView( + .padding(.horizontal, 24) + } + + if creatorProfile.creator.creatorId == UserDefaults.int(forKey: .userId) || creatorProfile.contentList.count > 0 { + UserProfileContentView( userId: userId, - cheers: creatorProfile.cheers, - errorPopup: { message in - viewModel.errorMessage = message - viewModel.isShowPopup = true - }, - reportPopup: { cheerId in - viewModel.cheersId = cheerId - viewModel.isShowCheersReportView = true - }, - deletePopup: { cheerId in - viewModel.cheersId = cheerId - viewModel.isShowCheersDeleteView = true - }, - profilePopup: { - self.memberId = $0 - self.isShowMemberProfilePopup = true - }, - isLoading: $viewModel.isLoading + items: creatorProfile.contentList, + totalContentCount: creatorProfile.totalContentCount, + ownedContentCount: creatorProfile.ownedContentCount + ) + .padding(.horizontal, 24) + } + + VStack(alignment: .leading, spacing: 14) { + HStack(spacing: 0) { + Text("커뮤니티") + .font(.custom(Font.preBold.rawValue, size: 26)) + .foregroundColor(Color.white) + .padding(.horizontal, 24) + + Spacer() + } + if viewModel.communityPostList.count > 0 { + ScrollView(.horizontal, showsIndicators: false) { + LazyHStack(spacing: 14) { + if UserDefaults.int(forKey: .userId) == creatorProfile.creator.creatorId { + CreatorCommunityWriteItemView() + .onTapGesture { + AppState.shared.setAppStep( + step: .creatorCommunityWrite( + onSuccess: creatorCommunityWriteSuccess + ) + ) + } + } + + ForEach(0.. 0 { + UserProfileDonationView(userId: userId, donationRankingResponse: creatorProfile.userDonationRanking) + } + + UserProfileFanTalkView( + userId: userId, + cheers: creatorProfile.cheers, + errorPopup: { message in + viewModel.errorMessage = message + viewModel.isShowPopup = true + }, + reportPopup: { cheerId in + viewModel.cheersId = cheerId + viewModel.isShowCheersReportView = true + }, + deletePopup: { cheerId in + viewModel.cheersId = cheerId + viewModel.isShowCheersDeleteView = true + }, + profilePopup: { + self.memberId = $0 + self.isShowMemberProfilePopup = true + }, + isLoading: $viewModel.isLoading + ) } } }