feat(live): 라이브룸 게스트 상단에 팔로우 버튼과 알림 옵션을 추가한다

This commit is contained in:
Yu Sung
2026-03-05 10:55:55 +09:00
parent f0763d75c2
commit ca565a2b5f
4 changed files with 84 additions and 2 deletions

View File

@@ -1278,7 +1278,12 @@ final class LiveRoomViewModel: NSObject, ObservableObject {
.store(in: &subscription)
}
func creatorFollow(creatorId: Int? = nil, isGetUserProfile: Bool = false) {
func creatorFollow(
creatorId: Int? = nil,
follow: Bool = true,
notify: Bool = true,
isGetUserProfile: Bool = false
) {
var userId = 0
if let creatorId = creatorId {
@@ -1290,7 +1295,7 @@ final class LiveRoomViewModel: NSObject, ObservableObject {
if userId > 0 {
isLoading = true
userRepository.creatorFollow(creatorId: userId)
userRepository.creatorFollow(creatorId: userId, follow: follow, notify: notify)
.sink { result in
switch result {
case .finished:

View File

@@ -24,6 +24,7 @@ struct LiveRoomInfoGuestView: View {
let creatorId: Int
let creatorNickname: String
let creatorProfileUrl: String
let followButtonType: FollowButtonImageType
let speakerList: [LiveRoomMember]
let muteSpeakerList: [UInt]
let activeSpeakerList: [UInt]
@@ -38,6 +39,7 @@ struct LiveRoomInfoGuestView: View {
let onClickMenuPan: () -> Void
let onClickTotalHeart: () -> Void
let onClickTotalDonation: () -> Void
let onClickFollow: () -> Void
let onClickChangeListener: () -> Void
let onClickToggleV2VCaption: () -> Void
let onClickToggleSignature: () -> Void
@@ -210,6 +212,13 @@ struct LiveRoomInfoGuestView: View {
.stroke(Color.graybb, lineWidth: 1)
)
.onTapGesture { onClickTotalDonation() }
if creatorId != UserDefaults.int(forKey: .userId) {
let asset = FollowButtonImageAsset(type: followButtonType)
asset.imageView(defaultSize: CGSize(width: 83.3, height: 26.7))
.contentShape(Rectangle())
.onTapGesture { onClickFollow() }
}
}
}
@@ -245,6 +254,7 @@ struct LiveRoomInfoGuestView_Previews: PreviewProvider {
creatorId: 1,
creatorNickname: "도화",
creatorProfileUrl: "https://cf.sodalive.net/profile/26/26-profile-ddf78b4d-0300-4c50-9c84-5d8a95fd5fe2-4892-1705256364320",
followButtonType: .follow,
speakerList: [
LiveRoomMember(
id: 1,
@@ -276,6 +286,7 @@ struct LiveRoomInfoGuestView_Previews: PreviewProvider {
onClickMenuPan: {},
onClickTotalHeart: {},
onClickTotalDonation: {},
onClickFollow: {},
onClickChangeListener: {},
onClickToggleV2VCaption: {},
onClickToggleSignature: {}

View File

@@ -24,6 +24,8 @@ struct LiveRoomViewV2: View {
@State private var showWaterHeart: Bool = false
@State private var waterProgress: CGFloat = 0
@State private var wavePhase: CGFloat = 0
@State private var isShowFollowNotifyDialog: Bool = false
@State private var guestFollowButtonTypeOverride: FollowButtonImageType? = nil
let heartWaveTimer = Timer.publish(every: 1/60, on: .main, in: .common).autoconnect()
var body: some View {
@@ -101,6 +103,7 @@ struct LiveRoomViewV2: View {
creatorId: liveRoomInfo.creatorId,
creatorNickname: liveRoomInfo.creatorNickname,
creatorProfileUrl: liveRoomInfo.creatorProfileUrl,
followButtonType: guestFollowButtonType(liveRoomInfo: liveRoomInfo),
speakerList: liveRoomInfo.speakerList,
muteSpeakerList: viewModel.muteSpeakers,
activeSpeakerList: viewModel.activeSpeakers,
@@ -131,6 +134,16 @@ struct LiveRoomViewV2: View {
onClickTotalDonation: {
viewModel.isShowDonationRankingPopup = true
},
onClickFollow: {
let buttonType = guestFollowButtonType(liveRoomInfo: liveRoomInfo)
if buttonType == .follow {
guestFollowButtonTypeOverride = .following
viewModel.creatorFollow(follow: true, notify: true)
} else {
isShowFollowNotifyDialog = true
}
},
onClickChangeListener: {
viewModel.setListener()
},
@@ -735,6 +748,26 @@ struct LiveRoomViewV2: View {
}
}
}
if isShowFollowNotifyDialog,
let liveRoomInfo = viewModel.liveRoomInfo,
liveRoomInfo.creatorId != UserDefaults.int(forKey: .userId) {
CreatorFollowNotifyDialog(
isShowing: $isShowFollowNotifyDialog,
onClickNotifyAll: {
guestFollowButtonTypeOverride = .following
viewModel.creatorFollow(follow: true, notify: true)
},
onClickNotifyNone: {
guestFollowButtonTypeOverride = .followingNoAlarm
viewModel.creatorFollow(follow: true, notify: false)
},
onClickUnFollow: {
guestFollowButtonTypeOverride = .follow
viewModel.creatorFollow(follow: false, notify: false)
}
)
}
}
if viewModel.isShowRouletteSettings {
@@ -890,6 +923,11 @@ struct LiveRoomViewV2: View {
.sheet(isPresented: $viewModel.isShowDonationMessagePopup) {
LiveRoomDonationMessageDialog(viewModel: viewModel, isShowing: $viewModel.isShowDonationMessagePopup)
}
.onChange(of: viewModel.liveRoomInfo?.isFollowing) { isFollowing in
if isFollowing == false {
guestFollowButtonTypeOverride = nil
}
}
}
private func estimatedHeight(for text: String, width: CGFloat) -> CGFloat {
@@ -941,6 +979,14 @@ struct LiveRoomViewV2: View {
}
private extension LiveRoomViewV2 {
func guestFollowButtonType(liveRoomInfo: GetRoomInfoResponse) -> FollowButtonImageType {
if liveRoomInfo.isFollowing {
return guestFollowButtonTypeOverride ?? .following
}
return .follow
}
var isV2VCaptionVisible: Bool {
viewModel.isV2VCaptionOn &&
!viewModel.v2vCaptionText.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty

View File

@@ -0,0 +1,20 @@
# 20260305 라이브룸 팔로우 버튼 추가
## 구현 체크리스트
- [x] LiveRoom 상단 참여자 수 영역 구조 확인
- [x] UserProfileView의 팔로우 버튼 이미지/다이얼로그 패턴 확인
- [x] LiveRoomViewV2에 팔로우/팔로잉 버튼 노출 조건 추가 (방장 본인 제외)
- [x] 팔로잉 상태에서 언팔로우 다이얼로그 노출 및 액션 연결
- [x] 관련 파일 진단/빌드 검증 수행
## 검증 기록
- 무엇/왜/어떻게: 라이브룸 V2 게스트 상단에 `FollowButtonImageAsset` 기반 팔로우/팔로잉 이미지 버튼을 추가하고, 팔로잉 상태 탭 시 `CreatorFollowNotifyDialog`를 통해 알림 전체/알림 끔/언팔로우를 선택하도록 연결했다. 방장 본인은 버튼이 보이지 않도록 조건을 유지했다.
- 실행 명령: `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive" -configuration Debug build`
- 결과: `** BUILD SUCCEEDED **`
- 실행 명령: `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive" test`
- 결과: `Scheme SodaLive is not currently configured for the test action.` (현재 스킴 테스트 액션 미구성으로 실행 불가)
- 실행 명령: `lsp_diagnostics` (수정 파일 3개)
- 결과: SourceKit 환경에서 외부 모듈(`Kingfisher`, `Moya`) 해석 불가로 오탐 오류 다수 발생. 실제 컴파일은 `xcodebuild` 성공 기준으로 검증.
- 무엇/왜/어떻게: 후속 이슈로 "알림 없음" 선택 후 버튼 이미지가 `followingNoAlarm`으로 유지되지 않는 문제를 수정했다. `GetRoomInfoResponse`에 notify 상태 필드가 없어, 게스트 상단 버튼에 로컬 override 상태를 두고 `notify=false` 선택 시 `FollowButtonImageType.followingNoAlarm`을 우선 표시하도록 반영했다.
- 실행 명령: `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive" -configuration Debug build`
- 결과: `** BUILD SUCCEEDED **`