diff --git a/SodaLive/Sources/Content/Detail/LiveRoomDonationDialogView.swift b/SodaLive/Sources/Content/Detail/LiveRoomDonationDialogView.swift index a84a396..4fb24dc 100644 --- a/SodaLive/Sources/Content/Detail/LiveRoomDonationDialogView.swift +++ b/SodaLive/Sources/Content/Detail/LiveRoomDonationDialogView.swift @@ -23,6 +23,9 @@ struct LiveRoomDonationDialogView: View { @Binding var isShowing: Bool let isAudioContentDonation: Bool let messageLimit: Int + let secretLabel: String + let secretMinimumCanMessage: String + let shouldPrefixSecretInMessagePlaceholder: Bool let onClickDonation: (Int, String, Bool) -> Void @StateObject var keyboardHandler = KeyboardHandler() @@ -31,11 +34,17 @@ struct LiveRoomDonationDialogView: View { isShowing: Binding, isAudioContentDonation: Bool, messageLimit: Int = 1000, + secretLabel: String = I18n.LiveRoom.secretMissionLabel, + secretMinimumCanMessage: String = I18n.LiveRoom.secretMissionMinimumCanMessage, + shouldPrefixSecretInMessagePlaceholder: Bool = true, onClickDonation: @escaping (Int, String, Bool) -> Void ) { self._isShowing = isShowing self.isAudioContentDonation = isAudioContentDonation self.messageLimit = messageLimit + self.secretLabel = secretLabel + self.secretMinimumCanMessage = secretMinimumCanMessage + self.shouldPrefixSecretInMessagePlaceholder = shouldPrefixSecretInMessagePlaceholder self.onClickDonation = onClickDonation } @@ -105,7 +114,7 @@ struct LiveRoomDonationDialogView: View { .resizable() .frame(width: 20, height: 20) - Text("비밀미션") + Text(secretLabel) .appFont(size: 14.7, weight: .medium) .foregroundColor(isSecret ? Color.button : Color.grayee) } @@ -217,7 +226,10 @@ struct LiveRoomDonationDialogView: View { .stroke(Color.graybb, lineWidth: 1) ) - TextField("함께 보낼 \(isSecret ? "비밀 " : "")메시지 입력(최대 \(messageLimit)자)", text: $donationMessage) + TextField( + "함께 보낼 \((isSecret && shouldPrefixSecretInMessagePlaceholder) ? "비밀 " : "")메시지 입력(최대 \(messageLimit)자)", + text: $donationMessage + ) .appFont(size: 13.3, weight: .medium) .foregroundColor(Color.grayee) .padding(13.3) @@ -256,7 +268,7 @@ struct LiveRoomDonationDialogView: View { .onTapGesture { if !donationCan.trimmingCharacters(in: .whitespaces).isEmpty, let can = Int(donationCan) { if isSecret && can < 10 { - errorMessage = "비밀 미션은 최소 10캔 이상부터 이용이 가능합니다." + errorMessage = secretMinimumCanMessage isShowErrorPopup = true } else if can < 1 { errorMessage = "1캔 이상 후원하실 수 있습니다." diff --git a/SodaLive/Sources/Explorer/Profile/ChannelDonation/UserProfileChannelDonationView.swift b/SodaLive/Sources/Explorer/Profile/ChannelDonation/UserProfileChannelDonationView.swift index 78f1400..41742d5 100644 --- a/SodaLive/Sources/Explorer/Profile/ChannelDonation/UserProfileChannelDonationView.swift +++ b/SodaLive/Sources/Explorer/Profile/ChannelDonation/UserProfileChannelDonationView.swift @@ -3,8 +3,21 @@ import SwiftUI struct UserProfileChannelDonationView: View { let creatorId: Int let donationItems: [GetChannelDonationListItem] + let isShowDonationButton: Bool let onTapDonationButton: () -> Void + init( + creatorId: Int, + donationItems: [GetChannelDonationListItem], + isShowDonationButton: Bool = true, + onTapDonationButton: @escaping () -> Void + ) { + self.creatorId = creatorId + self.donationItems = donationItems + self.isShowDonationButton = isShowDonationButton + self.onTapDonationButton = onTapDonationButton + } + var body: some View { VStack(alignment: .leading, spacing: 14) { HStack(spacing: 0) { @@ -48,22 +61,24 @@ struct UserProfileChannelDonationView: View { } } - HStack(spacing: 6.7) { - Image("ic_donation_white") - .resizable() - .frame(width: 20, height: 20) + if isShowDonationButton { + HStack(spacing: 6.7) { + Image("ic_donation_white") + .resizable() + .frame(width: 20, height: 20) - Text(I18n.MemberChannel.channelDonationButton) - .appFont(size: 16, weight: .bold) - .foregroundColor(.white) - } - .frame(maxWidth: .infinity) - .padding(.vertical, 16) - .background(Color(hex: "525252")) - .cornerRadius(16) - .padding(.horizontal, 24) - .onTapGesture { - onTapDonationButton() + Text(I18n.MemberChannel.channelDonationButton) + .appFont(size: 16, weight: .bold) + .foregroundColor(.white) + } + .frame(maxWidth: .infinity) + .padding(.vertical, 16) + .background(Color(hex: "525252")) + .cornerRadius(16) + .padding(.horizontal, 24) + .onTapGesture { + onTapDonationButton() + } } } } diff --git a/SodaLive/Sources/Explorer/Profile/UserProfileView.swift b/SodaLive/Sources/Explorer/Profile/UserProfileView.swift index 742a514..9c6e7e3 100644 --- a/SodaLive/Sources/Explorer/Profile/UserProfileView.swift +++ b/SodaLive/Sources/Explorer/Profile/UserProfileView.swift @@ -199,6 +199,7 @@ struct UserProfileView: View { UserProfileChannelDonationView( creatorId: creatorProfile.creator.creatorId, donationItems: creatorProfile.channelDonationList, + isShowDonationButton: creatorProfile.creator.creatorId != UserDefaults.int(forKey: .userId), onTapDonationButton: { channelDonationViewModel.setCreatorId(creatorProfile.creator.creatorId, shouldFetch: false) isShowChannelDonationDialog = true @@ -439,6 +440,9 @@ struct UserProfileView: View { isShowing: $isShowChannelDonationDialog, isAudioContentDonation: false, messageLimit: 100, + secretLabel: I18n.MemberChannel.secretDonationLabel, + secretMinimumCanMessage: I18n.MemberChannel.secretDonationMinimumCanMessage, + shouldPrefixSecretInMessagePlaceholder: false, onClickDonation: { can, message, isSecret in channelDonationViewModel.postChannelDonation( can: can, diff --git a/SodaLive/Sources/I18n/I18n.swift b/SodaLive/Sources/I18n/I18n.swift index 7c5b507..a72d468 100644 --- a/SodaLive/Sources/I18n/I18n.swift +++ b/SodaLive/Sources/I18n/I18n.swift @@ -725,6 +725,18 @@ enum I18n { ) } + static var secretMissionLabel: String { + pick(ko: "비밀미션", en: "Secret mission", ja: "秘密ミッション") + } + + static var secretMissionMinimumCanMessage: String { + pick( + ko: "비밀 미션은 최소 10캔 이상부터 이용이 가능합니다.", + en: "Secret mission is available from at least 10 cans.", + ja: "秘密ミッションは最低10canから利用できます。" + ) + } + static var likeHeartNoticeDesc: String { pick( ko: "'좋아해요'는 유료 후원입니다.\n클릭시 1캔이 소진됩니다.", @@ -979,6 +991,14 @@ If you block this user, the following features will be restricted. static var channelDonationHeader: String { pick(ko: "채널 후원", en: "Channel Donation", ja: "チャンネル支援") } static var channelDonationButton: String { pick(ko: "채널 후원하기", en: "Donate to Channel", ja: "チャンネルを支援する") } + static var secretDonationLabel: String { pick(ko: "비밀후원", en: "Secret donation", ja: "シークレット支援") } + static var secretDonationMinimumCanMessage: String { + pick( + ko: "비밀 후원은 최소 10캔 이상부터 이용이 가능합니다.", + en: "Secret donation is available from at least 10 cans.", + ja: "シークレット支援は最低10canから利用できます。" + ) + } static var channelDonationEmpty: String { pick(ko: "채널 후원이 없습니다.", en: "No channel donations.", ja: "チャンネル支援はありません。") } static var channelDonationAllTitle: String { pick(ko: "채널 후원 전체보기", en: "All Channel Donations", ja: "チャンネル支援一覧") } static var totalLabel: String { pick(ko: "전체", en: "Total", ja: "全体") } diff --git a/docs/20260225_후원비밀문구국제화수정.md b/docs/20260225_후원비밀문구국제화수정.md new file mode 100644 index 0000000..5c6e0cd --- /dev/null +++ b/docs/20260225_후원비밀문구국제화수정.md @@ -0,0 +1,58 @@ +# 20260225 후원 비밀 문구 국제화 수정 + +## 구현 체크리스트 +- [x] 채널 후원/라이브 룸 후원 비밀 문구 분기 위치 확인 +- [x] `I18n`에 채널 후원용 `비밀후원` 문구 추가 +- [x] 공용 후원 다이얼로그(`LiveRoomDonationDialogView`)에 컨텍스트별 비밀 문구 주입 파라미터 추가 +- [x] 채널 후원 진입점(`UserProfileView`)에서 `비밀후원` 문구 전달 +- [x] 진단/빌드/테스트 검증 수행 및 결과 기록 + +## 검증 기록 +- 무엇: 수정 파일 3개(`I18n.swift`, `LiveRoomDonationDialogView.swift`, `UserProfileView.swift`)에 대해 `lsp_diagnostics` 오류 확인 + 왜: 변경 직후 타입/문법 수준 오류를 선검증하기 위함 + 어떻게: `lsp_diagnostics` 실행 + 결과: SourceKit 환경 의존 오류 확인 (`No such module 'Kingfisher'`, `Cannot find 'LanguageHeaderProvider' in scope`), 이후 실제 `xcodebuild` 빌드는 성공 + +- 무엇: 기본 스킴 빌드 검증 + 왜: 후원 다이얼로그/국제화 문자열 변경이 앱 컴파일에 문제 없는지 확인하기 위함 + 어떻게: `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive" -configuration Debug build` + 결과: `** BUILD SUCCEEDED **` + +- 무엇: dev 스킴 빌드 검증 + 왜: 동일 변경이 `SodaLive-dev` 스킴에도 회귀 없이 반영되는지 확인하기 위함 + 어떻게: `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build` + 결과: `** BUILD SUCCEEDED **` + +- 무엇: 테스트 액션 실행 가능 여부 확인 + 왜: 저장소 검증 절차에 테스트 명령이 포함되므로 실행 결과 확인 필요 + 어떻게: `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive" test` 및 `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" test` + 결과: 두 스킴 모두 `Scheme ... is not currently configured for the test action.`로 테스트 액션 미구성 상태 + +## 추가 요구사항 반영 체크리스트 (2차) +- [x] 비밀미션 체크 시 메시지 입력창 플레이스홀더는 기존과 동일하게 `비밀` 접두어를 유지 +- [x] 비밀후원 체크 시 메시지 입력창 플레이스홀더는 체크하지 않은 상태와 동일하게 유지 + +- 무엇: 공용 후원 다이얼로그 플레이스홀더 분기 옵션 추가 + 왜: 비밀미션/비밀후원 컨텍스트별로 메시지 입력창 문구 동작을 분리해야 하기 때문 + 어떻게: `LiveRoomDonationDialogView`에 `shouldPrefixSecretInMessagePlaceholder` 파라미터(기본 `true`)를 추가하고 플레이스홀더를 `isSecret && shouldPrefixSecretInMessagePlaceholder` 조건으로 변경 + 결과: 기본 흐름(비밀미션)은 기존 동작 유지, 옵션 비활성 시(비밀후원) 접두어 미표시 + +- 무엇: 채널 후원 진입점에 플레이스홀더 분기 옵션 적용 + 왜: 채널 후원은 비밀후원 체크 시에도 일반 메시지 플레이스홀더를 유지해야 하기 때문 + 어떻게: `UserProfileView`의 `LiveRoomDonationDialogView` 호출부에 `shouldPrefixSecretInMessagePlaceholder: false` 전달 + 결과: 채널 후원 다이얼로그에서 비밀후원 체크 여부와 무관하게 플레이스홀더가 동일하게 유지 + +- 무엇: 2차 반영 후 수정 파일 진단 확인 + 왜: 분기 파라미터 추가 이후 정적 진단 상태 확인 필요 + 어떻게: `lsp_diagnostics` 실행(`LiveRoomDonationDialogView.swift`, `UserProfileView.swift`, `I18n.swift`) + 결과: SourceKit 환경 의존 오류 확인 (`No such module 'Kingfisher'`, `Cannot find 'LanguageHeaderProvider' in scope`), 이후 실제 빌드 성공으로 컴파일 정상 확인 + +- 무엇: 2차 반영 후 기본/dev 스킴 빌드 재검증 + 왜: 플레이스홀더 분기 변경이 스킴별 컴파일에 영향 없는지 확인 필요 + 어떻게: `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive" -configuration Debug build` 및 `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build` + 결과: 두 스킴 모두 `** BUILD SUCCEEDED **` + +- 무엇: 2차 반영 후 테스트 액션 재확인 + 왜: 저장소 기준 테스트 실행 가능 상태를 변경 후에도 확인하기 위함 + 어떻게: `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive" test` 및 `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" test` + 결과: 두 스킴 모두 `Scheme ... is not currently configured for the test action.`로 테스트 액션 미구성 상태 diff --git a/docs/20260226_내페이지채널후원버튼숨김.md b/docs/20260226_내페이지채널후원버튼숨김.md new file mode 100644 index 0000000..58c752b --- /dev/null +++ b/docs/20260226_내페이지채널후원버튼숨김.md @@ -0,0 +1,38 @@ +# 20260226 내 페이지 채널 후원 버튼 숨김 + +## 구현 체크리스트 +- [x] 크리에이터 채널 내 `채널 후원하기` 버튼 렌더링 위치 및 표시 조건 확인 +- [x] `UserProfileChannelDonationView`에 버튼 표시 제어 파라미터 추가 +- [x] `UserProfileView`에서 내 페이지 여부에 따라 버튼 표시값 전달 +- [x] 진단/빌드/테스트 검증 수행 및 결과 기록 + +## 검증 기록 +- 무엇: `UserProfileChannelDonationView`/`UserProfileView` 표시 조건 위치 확인 + 왜: 내 페이지에서만 버튼을 숨기는 최소 수정 지점을 특정하기 위함 + 어떻게: `grep`/`read`로 `채널 후원하기` 렌더링 및 `creatorId == UserDefaults.int(forKey: .userId)` 비교 로직 확인 + 결과: 버튼 렌더링은 `UserProfileChannelDonationView`, 내 페이지 판별값은 `UserProfileView`에서 확보 + +- 무엇: 버튼 표시 제어 파라미터 적용 + 왜: 채널 후원 영역은 유지하면서 버튼만 숨겨야 하기 때문 + 어떻게: `UserProfileChannelDonationView`에 `isShowDonationButton` 파라미터 추가 후 버튼 `if` 분기, `UserProfileView`에서 내 페이지일 때 `false` 전달 + 결과: 내 페이지에서는 채널 후원하기 버튼 미노출, 타인 페이지는 기존과 동일 + +- 무엇: 변경 직후 정적 진단 확인 + 왜: 수정 파일의 즉시 오류 여부 확인 필요 + 어떻게: `lsp_diagnostics` 실행 + 결과: SourceKit 환경 의존 오류 확인(`No such module 'Kingfisher'` 등), 이후 실제 빌드 성공으로 컴파일 정상 확인 + +- 무엇: 빌드 검증(기본 스킴) + 왜: 변경이 앱 컴파일에 미치는 영향 확인 + 어떻게: `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive" -configuration Debug build` + 결과: 1차 `BUILD FAILED`(`extra argument 'isShowDonationButton' in call`) 확인 후 초기화 시그니처 수정, 재실행 `** BUILD SUCCEEDED **` + +- 무엇: 빌드 검증(dev 스킴) + 왜: 동일 변경의 dev 스킴 회귀 여부 확인 + 어떻게: `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build` + 결과: `** BUILD SUCCEEDED **` + +- 무엇: 테스트 액션 실행 가능 여부 확인 + 왜: 저장소 검증 절차상 테스트 명령 수행 결과 확인 필요 + 어떻게: `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive" test` 및 `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" test` + 결과: 두 스킴 모두 `Scheme ... is not currently configured for the test action.`로 테스트 액션 미구성