feat(i18n): 콘텐츠 상세/댓글 하드코딩 문구를 I18n 키로 통일한다
This commit is contained in:
@@ -77,13 +77,13 @@ final class ContentCurationViewModel: ObservableObject {
|
||||
if let message = decoded.message {
|
||||
self.errorMessage = message
|
||||
} else {
|
||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
||||
self.errorMessage = I18n.Common.commonError
|
||||
}
|
||||
|
||||
self.isShowPopup = true
|
||||
}
|
||||
} catch {
|
||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
||||
self.errorMessage = I18n.Common.commonError
|
||||
self.isShowPopup = true
|
||||
}
|
||||
|
||||
|
||||
@@ -19,11 +19,11 @@ struct AudioContentDeleteDialogView: View {
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: 0) {
|
||||
Text("콘텐츠 삭제")
|
||||
Text(I18n.ContentDetail.DeleteDialog.title)
|
||||
.appFont(size: 18.3, weight: .bold)
|
||||
.foregroundColor(Color(hex: "eeeeee"))
|
||||
|
||||
Text("[\(title)]을 삭제하시겠습니까?")
|
||||
Text(I18n.ContentDetail.DeleteDialog.confirmQuestion(title))
|
||||
.appFont(size: 13.3, weight: .medium)
|
||||
.foregroundColor(Color(hex: "eeeeee"))
|
||||
.padding(.top, 21.3)
|
||||
@@ -36,7 +36,7 @@ struct AudioContentDeleteDialogView: View {
|
||||
isAgree.toggle()
|
||||
}
|
||||
|
||||
Text("삭제된 콘텐츠는 되돌릴 수 없음을 알고 있습니다.")
|
||||
Text(I18n.ContentDetail.DeleteDialog.irreversibleAcknowledgement)
|
||||
.appFont(size: 12, weight: .medium)
|
||||
.foregroundColor(Color(hex: "eeeeee"))
|
||||
.onTapGesture {
|
||||
@@ -48,7 +48,7 @@ struct AudioContentDeleteDialogView: View {
|
||||
.cornerRadius(6.7)
|
||||
.padding(.top, 13.3)
|
||||
|
||||
Text("콘텐츠를 삭제하더라도 이미 구매한\n사용자는 콘텐츠를 이용할 수 있습니다.")
|
||||
Text(I18n.ContentDetail.DeleteDialog.purchasedUserNotice)
|
||||
.appFont(size: 12, weight: .medium)
|
||||
.foregroundColor(Color(hex: "dd4500"))
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
@@ -56,7 +56,7 @@ struct AudioContentDeleteDialogView: View {
|
||||
.padding(.top, 13.3)
|
||||
|
||||
HStack(spacing: 12) {
|
||||
Text("취소")
|
||||
Text(I18n.Common.cancel)
|
||||
.appFont(size: 18.3, weight: .bold)
|
||||
.foregroundColor(Color(hex: "9970ff"))
|
||||
.padding(.horizontal, 55)
|
||||
@@ -70,7 +70,7 @@ struct AudioContentDeleteDialogView: View {
|
||||
isShowing = false
|
||||
}
|
||||
|
||||
Text("확인")
|
||||
Text(I18n.Common.confirm)
|
||||
.appFont(size: 18.3, weight: .bold)
|
||||
.foregroundColor(Color(hex: "eeeeee"))
|
||||
.padding(.horizontal, 55)
|
||||
|
||||
@@ -13,15 +13,7 @@ struct AudioContentReportDialogView: View {
|
||||
let confirmAction: (String) -> Void
|
||||
|
||||
@State private var selectedIndex: Int? = nil
|
||||
let reasons = [
|
||||
"괴롭힘 및 사이버 폭력",
|
||||
"개인정보 침해",
|
||||
"명의도용",
|
||||
"폭력적 위협",
|
||||
"아동학대",
|
||||
"보호대상 집단에 대한 증오심 표현",
|
||||
"스팸 및 사기"
|
||||
]
|
||||
let reasons = I18n.ContentDetail.ReportDialog.reasons
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
@@ -31,7 +23,7 @@ struct AudioContentReportDialogView: View {
|
||||
.onTapGesture { isShowing = false }
|
||||
|
||||
VStack(spacing: 13.3) {
|
||||
Text("콘텐츠 신고")
|
||||
Text(I18n.ContentDetail.ReportDialog.title)
|
||||
.appFont(size: 18.3, weight: .bold)
|
||||
.foregroundColor(Color(hex: "eeeeee"))
|
||||
|
||||
@@ -59,13 +51,13 @@ struct AudioContentReportDialogView: View {
|
||||
.cornerRadius(6.7)
|
||||
.padding(.vertical, 21.3)
|
||||
|
||||
Text("신고한 콘텐츠를 관리자가 확인 후, 서비스정책을\n위반한 경우 삭제 조치할 예정입니다.")
|
||||
Text(I18n.ContentDetail.ReportDialog.notice)
|
||||
.appFont(size: 13.3, weight: .medium)
|
||||
.foregroundColor(Color(hex: "dd4500"))
|
||||
.multilineTextAlignment(.center)
|
||||
|
||||
HStack(spacing: 12) {
|
||||
Text("취소")
|
||||
Text(I18n.Common.cancel)
|
||||
.appFont(size: 18.3, weight: .bold)
|
||||
.foregroundColor(Color(hex: "9970ff"))
|
||||
.padding(.vertical, 16)
|
||||
@@ -79,7 +71,7 @@ struct AudioContentReportDialogView: View {
|
||||
isShowing = false
|
||||
}
|
||||
|
||||
Text("신고")
|
||||
Text(I18n.ContentDetail.ReportDialog.reportAction)
|
||||
.appFont(size: 18.3, weight: .bold)
|
||||
.foregroundColor(Color(hex: "eeeeee"))
|
||||
.padding(.vertical, 16)
|
||||
|
||||
@@ -51,7 +51,7 @@ struct AudioContentCommentItemView: View {
|
||||
.foregroundColor(Color.gray90)
|
||||
|
||||
if commentItem.isSecret {
|
||||
Text("비밀댓글")
|
||||
Text(I18n.ContentDetail.Comment.secretComment)
|
||||
.appFont(size: 11, weight: .medium)
|
||||
.foregroundColor(Color.grayee)
|
||||
.padding(.horizontal, 4)
|
||||
@@ -104,7 +104,7 @@ struct AudioContentCommentItemView: View {
|
||||
HStack(spacing: 0) {
|
||||
if isModeModify {
|
||||
HStack(spacing: 0) {
|
||||
TextField("댓글을 입력해 보세요.", text: $comment)
|
||||
TextField(I18n.ContentDetail.Comment.inputPlaceholder, text: $comment)
|
||||
.autocapitalization(.none)
|
||||
.disableAutocorrection(true)
|
||||
.appFont(size: 13.3, weight: .medium)
|
||||
@@ -150,8 +150,12 @@ struct AudioContentCommentItemView: View {
|
||||
audioContentId: audioContentId,
|
||||
parentComment: commentItem
|
||||
)
|
||||
) {
|
||||
Text(commentItem.replyCount > 0 ? "답글 \(commentItem.replyCount)개" : "답글 쓰기")
|
||||
) {
|
||||
Text(
|
||||
commentItem.replyCount > 0 ?
|
||||
I18n.ContentDetail.Comment.replyCount(commentItem.replyCount) :
|
||||
I18n.ContentDetail.Comment.writeReply
|
||||
)
|
||||
.appFont(size: 13.3, weight: .medium)
|
||||
.foregroundColor(Color.button)
|
||||
}
|
||||
@@ -172,7 +176,7 @@ struct AudioContentCommentItemView: View {
|
||||
if isShowPopupMenu {
|
||||
VStack(spacing: 10) {
|
||||
if commentItem.writerId == UserDefaults.int(forKey: .userId) {
|
||||
Text("수정")
|
||||
Text(I18n.ContentDetail.Comment.edit)
|
||||
.appFont(size: 14, weight: .medium)
|
||||
.foregroundColor(Color.gray77)
|
||||
.onTapGesture {
|
||||
@@ -184,7 +188,7 @@ struct AudioContentCommentItemView: View {
|
||||
if contentCreatorId == UserDefaults.int(forKey: .userId) ||
|
||||
commentItem.writerId == UserDefaults.int(forKey: .userId)
|
||||
{
|
||||
Text("삭제")
|
||||
Text(I18n.Common.delete)
|
||||
.appFont(size: 14, weight: .medium)
|
||||
.foregroundColor(Color.gray77)
|
||||
.onTapGesture {
|
||||
|
||||
@@ -29,7 +29,7 @@ struct AudioContentCommentListView: View {
|
||||
ZStack {
|
||||
VStack(spacing: 0) {
|
||||
HStack(spacing: 0) {
|
||||
Text("댓글")
|
||||
Text(I18n.ContentDetail.Comment.title)
|
||||
.appFont(size: 14.7, weight: .medium)
|
||||
.foregroundColor(.white)
|
||||
.padding(.leading, 13.3)
|
||||
@@ -65,7 +65,7 @@ struct AudioContentCommentListView: View {
|
||||
viewModel.isSecret.toggle()
|
||||
}
|
||||
|
||||
Text("비밀댓글")
|
||||
Text(I18n.ContentDetail.Comment.secretComment)
|
||||
.appFont(size: 12, weight: .medium)
|
||||
.foregroundColor(viewModel.isSecret ? Color.button : Color.grayee)
|
||||
.onTapGesture {
|
||||
@@ -85,7 +85,7 @@ struct AudioContentCommentListView: View {
|
||||
.clipShape(Circle())
|
||||
|
||||
HStack(spacing: 0) {
|
||||
TextField("댓글을 입력해 보세요.", text: $viewModel.comment)
|
||||
TextField(I18n.ContentDetail.Comment.inputPlaceholder, text: $viewModel.comment)
|
||||
.autocapitalization(.none)
|
||||
.disableAutocorrection(true)
|
||||
.appFont(size: 13.3, weight: .medium)
|
||||
|
||||
@@ -64,13 +64,13 @@ class AudioContentCommentListViewModel: ObservableObject {
|
||||
if let message = decoded.message {
|
||||
self.errorMessage = message
|
||||
} else {
|
||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
||||
self.errorMessage = I18n.Common.commonError
|
||||
}
|
||||
|
||||
self.isShowPopup = true
|
||||
}
|
||||
} catch {
|
||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
||||
self.errorMessage = I18n.Common.commonError
|
||||
self.isShowPopup = true
|
||||
}
|
||||
|
||||
@@ -115,13 +115,13 @@ class AudioContentCommentListViewModel: ObservableObject {
|
||||
if let message = decoded.message {
|
||||
self.errorMessage = message
|
||||
} else {
|
||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
||||
self.errorMessage = I18n.Common.commonError
|
||||
}
|
||||
|
||||
self.isShowPopup = true
|
||||
}
|
||||
} catch {
|
||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
||||
self.errorMessage = I18n.Common.commonError
|
||||
self.isShowPopup = true
|
||||
}
|
||||
}
|
||||
@@ -135,13 +135,13 @@ class AudioContentCommentListViewModel: ObservableObject {
|
||||
isActive: Bool? = nil
|
||||
) {
|
||||
if comment == nil && isActive == nil {
|
||||
errorMessage = "변경사항이 없습니다."
|
||||
errorMessage = I18n.ContentDetail.Comment.noChanges
|
||||
isShowPopup = true
|
||||
return
|
||||
}
|
||||
|
||||
if let comment = comment, comment.trimmingCharacters(in: .whitespaces).isEmpty {
|
||||
errorMessage = "내용을 입력하세요."
|
||||
errorMessage = I18n.ContentDetail.Comment.inputContent
|
||||
isShowPopup = true
|
||||
return
|
||||
}
|
||||
@@ -187,14 +187,14 @@ class AudioContentCommentListViewModel: ObservableObject {
|
||||
if let message = decoded.message {
|
||||
self.errorMessage = message
|
||||
} else {
|
||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
||||
self.errorMessage = I18n.Common.commonError
|
||||
}
|
||||
|
||||
self.isShowPopup = true
|
||||
}
|
||||
} catch {
|
||||
self.isLoading = false
|
||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
||||
self.errorMessage = I18n.Common.commonError
|
||||
self.isShowPopup = true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ struct AudioContentListReplyView: View {
|
||||
HStack(spacing: 6.7) {
|
||||
Image("ic_back")
|
||||
|
||||
Text("답글")
|
||||
Text(I18n.ContentDetail.Comment.replyTitle)
|
||||
.appFont(size: 14.7, weight: .medium)
|
||||
.foregroundColor(.white)
|
||||
|
||||
@@ -55,7 +55,7 @@ struct AudioContentListReplyView: View {
|
||||
.clipShape(Circle())
|
||||
|
||||
HStack(spacing: 0) {
|
||||
TextField("댓글을 입력해 보세요.", text: $viewModel.comment)
|
||||
TextField(I18n.ContentDetail.Comment.inputPlaceholder, text: $viewModel.comment)
|
||||
.autocapitalization(.none)
|
||||
.disableAutocorrection(true)
|
||||
.appFont(size: 13.3, weight: .medium)
|
||||
|
||||
@@ -62,13 +62,13 @@ final class AudioContentListReplyViewModel: ObservableObject {
|
||||
if let message = decoded.message {
|
||||
self.errorMessage = message
|
||||
} else {
|
||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
||||
self.errorMessage = I18n.Common.commonError
|
||||
}
|
||||
|
||||
self.isShowPopup = true
|
||||
}
|
||||
} catch {
|
||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
||||
self.errorMessage = I18n.Common.commonError
|
||||
self.isShowPopup = true
|
||||
}
|
||||
|
||||
@@ -113,13 +113,13 @@ final class AudioContentListReplyViewModel: ObservableObject {
|
||||
if let message = decoded.message {
|
||||
self.errorMessage = message
|
||||
} else {
|
||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
||||
self.errorMessage = I18n.Common.commonError
|
||||
}
|
||||
|
||||
self.isShowPopup = true
|
||||
}
|
||||
} catch {
|
||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
||||
self.errorMessage = I18n.Common.commonError
|
||||
self.isShowPopup = true
|
||||
}
|
||||
}
|
||||
@@ -133,13 +133,13 @@ final class AudioContentListReplyViewModel: ObservableObject {
|
||||
isActive: Bool? = nil
|
||||
) {
|
||||
if comment == nil && isActive == nil {
|
||||
errorMessage = "변경사항이 없습니다."
|
||||
errorMessage = I18n.ContentDetail.Comment.noChanges
|
||||
isShowPopup = true
|
||||
return
|
||||
}
|
||||
|
||||
if let comment = comment, comment.trimmingCharacters(in: .whitespaces).isEmpty {
|
||||
errorMessage = "내용을 입력하세요."
|
||||
errorMessage = I18n.ContentDetail.Comment.inputContent
|
||||
isShowPopup = true
|
||||
return
|
||||
}
|
||||
@@ -185,14 +185,14 @@ final class AudioContentListReplyViewModel: ObservableObject {
|
||||
if let message = decoded.message {
|
||||
self.errorMessage = message
|
||||
} else {
|
||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
||||
self.errorMessage = I18n.Common.commonError
|
||||
}
|
||||
|
||||
self.isShowPopup = true
|
||||
}
|
||||
} catch {
|
||||
self.isLoading = false
|
||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
||||
self.errorMessage = I18n.Common.commonError
|
||||
self.isShowPopup = true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ struct ContentDetailCommentView: View {
|
||||
var body: some View {
|
||||
VStack(alignment: .leading, spacing: 10.3) {
|
||||
HStack(spacing: 5.3) {
|
||||
Text("댓글")
|
||||
Text(I18n.ContentDetail.Comment.title)
|
||||
.appFont(size: 12, weight: .medium)
|
||||
.foregroundColor(.white)
|
||||
|
||||
@@ -38,7 +38,7 @@ struct ContentDetailCommentView: View {
|
||||
.resizable()
|
||||
.frame(width: 20, height: 20)
|
||||
|
||||
Text("비밀댓글")
|
||||
Text(I18n.ContentDetail.Comment.secretComment)
|
||||
.appFont(size: 12, weight: .medium)
|
||||
.foregroundColor(isSecret ? Color.button : Color.grayee)
|
||||
}
|
||||
@@ -71,7 +71,7 @@ struct ContentDetailCommentView: View {
|
||||
.padding(.leading, 3)
|
||||
} else {
|
||||
HStack(spacing: 0) {
|
||||
TextField("댓글을 입력해 보세요.", text: $comment)
|
||||
TextField(I18n.ContentDetail.Comment.inputPlaceholder, text: $comment)
|
||||
.autocapitalization(.none)
|
||||
.disableAutocorrection(true)
|
||||
.appFont(size: 13.3, weight: .medium)
|
||||
|
||||
@@ -18,7 +18,7 @@ struct ContentDetailInfoLimitedEditionView: View {
|
||||
var body: some View {
|
||||
VStack(alignment: .leading, spacing: 13.3) {
|
||||
HStack(spacing: 0) {
|
||||
Text("한정판")
|
||||
Text(I18n.ContentDetail.LimitedEdition.title)
|
||||
.appFont(size: 13.3, weight: .medium)
|
||||
.foregroundColor(Color.button)
|
||||
|
||||
@@ -40,7 +40,7 @@ struct ContentDetailInfoLimitedEditionView: View {
|
||||
.foregroundColor(Color.grayd2)
|
||||
.padding(.leading, 2.3)
|
||||
} else if (remainingContentCount <= 0) {
|
||||
Text("Sold Out")
|
||||
Text(I18n.Content.Status.soldOut)
|
||||
.appFont(size: 12, weight: .medium)
|
||||
.foregroundColor(Color.grayd2)
|
||||
.padding(.horizontal, 5.3)
|
||||
@@ -51,7 +51,7 @@ struct ContentDetailInfoLimitedEditionView: View {
|
||||
.foregroundColor(Color.grayd2)
|
||||
)
|
||||
} else {
|
||||
Text("잔여수량")
|
||||
Text(I18n.ContentDetail.LimitedEdition.remainingCount)
|
||||
.appFont(size: 13.3, weight: .medium)
|
||||
.foregroundColor(Color.grayd2)
|
||||
|
||||
@@ -69,7 +69,7 @@ struct ContentDetailInfoLimitedEditionView: View {
|
||||
.padding(.top, 13.3)
|
||||
|
||||
if !buyerList.isEmpty {
|
||||
Text("구매자")
|
||||
Text(I18n.ContentDetail.LimitedEdition.buyers)
|
||||
.appFont(size: 18.3, weight: .bold)
|
||||
.foregroundColor(Color.grayee)
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ struct ContentDetailInfoView: View {
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
HStack(spacing: 5.3) {
|
||||
if let _ = audioContent.releaseDate {
|
||||
Text("오픈예정")
|
||||
Text(I18n.Common.openScheduled)
|
||||
.appFont(size: 12, weight: .medium)
|
||||
.foregroundColor(Color(hex: "3bb9f1"))
|
||||
.padding(.horizontal, 5.3)
|
||||
@@ -62,7 +62,7 @@ struct ContentDetailInfoView: View {
|
||||
}
|
||||
}
|
||||
|
||||
Text(orderType == .KEEP ? "소장중" : "대여중")
|
||||
Text(orderType == .KEEP ? I18n.Content.Status.owned : I18n.Content.Status.rented)
|
||||
.appFont(size: 12, weight: .medium)
|
||||
.foregroundColor(
|
||||
orderType == .KEEP ?
|
||||
@@ -113,7 +113,7 @@ struct ContentDetailInfoView: View {
|
||||
HStack(spacing: 4) {
|
||||
Image("ic_audio_content_share")
|
||||
|
||||
Text("공유")
|
||||
Text(I18n.ContentDetail.Info.share)
|
||||
.appFont(size: 13.3, weight: .medium)
|
||||
.foregroundColor(Color.grayd2)
|
||||
}
|
||||
@@ -129,7 +129,7 @@ struct ContentDetailInfoView: View {
|
||||
.resizable()
|
||||
.frame(width: 13.3, height: 13.3)
|
||||
|
||||
Text("후원")
|
||||
Text(I18n.ContentDetail.Info.donation)
|
||||
.appFont(size: 13.3, weight: .medium)
|
||||
.foregroundColor(Color.grayd2)
|
||||
}
|
||||
@@ -174,7 +174,7 @@ struct ContentDetailInfoView: View {
|
||||
|
||||
if isShowingPreviewAlert() {
|
||||
HStack(spacing: 0) {
|
||||
Text("미리듣기 중입니다.\n콘텐츠 구매 후 전체를 감상해 보세요.")
|
||||
Text(I18n.ContentDetail.Info.previewAlertMessage)
|
||||
.appFont(size: 12, weight: .medium)
|
||||
.foregroundColor(Color.graybb)
|
||||
.lineSpacing(5)
|
||||
|
||||
@@ -34,7 +34,7 @@ struct ContentDetailMenuView: View {
|
||||
HStack(spacing: 13.3) {
|
||||
Image(isPin ? "ic_pin_cancel" : "ic_pin")
|
||||
|
||||
Text(isPin ? "내 채널에 고정 취소" : "내 채널에 고정")
|
||||
Text(isPin ? I18n.ContentDetail.Menu.unpinFromMyChannel : I18n.ContentDetail.Menu.pinToMyChannel)
|
||||
.appFont(size: 16.7, weight: .medium)
|
||||
.foregroundColor(.white)
|
||||
|
||||
@@ -51,7 +51,7 @@ struct ContentDetailMenuView: View {
|
||||
HStack(spacing: 13.3) {
|
||||
Image("ic_make_message")
|
||||
|
||||
Text("수정")
|
||||
Text(I18n.ContentDetail.Menu.edit)
|
||||
.appFont(size: 16.7, weight: .medium)
|
||||
.foregroundColor(.white)
|
||||
|
||||
@@ -68,7 +68,7 @@ struct ContentDetailMenuView: View {
|
||||
HStack(spacing: 13.3) {
|
||||
Image("ic_trash_can")
|
||||
|
||||
Text("삭제")
|
||||
Text(I18n.Common.delete)
|
||||
.appFont(size: 16.7, weight: .medium)
|
||||
.foregroundColor(.white)
|
||||
|
||||
@@ -83,7 +83,7 @@ struct ContentDetailMenuView: View {
|
||||
}
|
||||
} else {
|
||||
HStack(spacing: 0) {
|
||||
Text("신고")
|
||||
Text(I18n.ContentDetail.Menu.report)
|
||||
.appFont(size: 16.7, weight: .medium)
|
||||
.foregroundColor(.white)
|
||||
|
||||
|
||||
@@ -16,12 +16,12 @@ struct ContentDetailMosaicView: View {
|
||||
VStack(spacing: 0) {
|
||||
Image("ic_notice_exclamation_mark")
|
||||
|
||||
Text("본 콘텐츠는 만 19세 미만의 청소년이\n이용할 수 없습니다.\n본인인증 후 콘텐츠를 이용해 주세요.")
|
||||
Text(I18n.ContentDetail.Mosaic.adultRestrictionNotice)
|
||||
.appFont(size: 18.7, weight: .medium)
|
||||
.foregroundColor(Color(hex: "bbbbbb"))
|
||||
.padding(.top, 21.7)
|
||||
|
||||
Text("본인인증")
|
||||
Text(I18n.ContentDetail.Mosaic.verifyIdentity)
|
||||
.appFont(size: 18.7, weight: .medium)
|
||||
.foregroundColor(Color.white)
|
||||
.padding(.horizontal, 13.3)
|
||||
|
||||
@@ -36,7 +36,7 @@ struct ContentDetailOtherContentView: View {
|
||||
.resizable()
|
||||
.frame(width: 60, height: 60)
|
||||
|
||||
Text("\(title)를 준비중입니다.\n조금만 기다려주세요.")
|
||||
Text(I18n.ContentDetail.OtherContent.preparingMessage(title))
|
||||
.multilineTextAlignment(.center)
|
||||
.appFont(size: 10.7, weight: .medium)
|
||||
.foregroundColor(Color(hex: "bbbbbb"))
|
||||
|
||||
@@ -62,7 +62,7 @@ struct ContentDetailPlayView: View {
|
||||
)
|
||||
|
||||
if let _ = audioContent.totalContentCount, let remainingContentCount = audioContent.remainingContentCount, remainingContentCount <= 0, audioContent.creator.creatorId != UserDefaults.int(forKey: .userId), !audioContent.existOrdered {
|
||||
Text("Sold Out")
|
||||
Text(I18n.Content.Status.soldOut)
|
||||
.appFont(size: 36.7, weight: .bold)
|
||||
.foregroundColor(.white)
|
||||
.frame(
|
||||
|
||||
@@ -32,7 +32,7 @@ struct ContentDetailPreviousNextContentButtonView: View {
|
||||
.multilineTextAlignment(.leading)
|
||||
.lineLimit(2)
|
||||
|
||||
Text("이전화")
|
||||
Text(I18n.ContentDetail.Navigation.previousEpisode)
|
||||
.appFont(size: 13.3, weight: .medium)
|
||||
.foregroundColor(.button)
|
||||
.multilineTextAlignment(.leading)
|
||||
@@ -71,7 +71,7 @@ struct ContentDetailPreviousNextContentButtonView: View {
|
||||
.multilineTextAlignment(.leading)
|
||||
.lineLimit(2)
|
||||
|
||||
Text("다음화")
|
||||
Text(I18n.ContentDetail.Navigation.nextEpisode)
|
||||
.appFont(size: 13.3, weight: .medium)
|
||||
.foregroundColor(.button)
|
||||
.multilineTextAlignment(.leading)
|
||||
|
||||
@@ -26,7 +26,11 @@ struct ContentDetailPurchaseButton: View {
|
||||
.foregroundColor(.white)
|
||||
.padding(.leading, 5.3)
|
||||
|
||||
Text(UserDefaults.int(forKey: .userId) == 17958 ? "원으로": "캔으로")
|
||||
Text(
|
||||
UserDefaults.int(forKey: .userId) == 17958 ?
|
||||
I18n.ContentDetail.Purchase.withWon :
|
||||
I18n.ContentDetail.Purchase.withCan
|
||||
)
|
||||
.appFont(size: 12, weight: .light)
|
||||
.foregroundColor(.white)
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ struct ContentDetailView: View {
|
||||
.resizable()
|
||||
.frame(width: 20, height: 20)
|
||||
|
||||
Text("콘텐츠 상세")
|
||||
Text(I18n.ContentDetail.title)
|
||||
.appFont(size: 18.3, weight: .bold)
|
||||
.foregroundColor(Color.grayee)
|
||||
}
|
||||
@@ -120,7 +120,7 @@ struct ContentDetailView: View {
|
||||
audioContent.orderType == nil &&
|
||||
audioContent.creator.creatorId != UserDefaults.int(forKey: .userId) {
|
||||
if let _ = audioContent.totalContentCount, let remainingContentCount = audioContent.remainingContentCount, remainingContentCount <= 0 {
|
||||
Text("해당 콘텐츠가 매진되었습니다.")
|
||||
Text(I18n.ContentDetail.soldOutNotice)
|
||||
.appFont(size: 13.3, weight: .bold)
|
||||
.foregroundColor(.white)
|
||||
.frame(maxWidth: .infinity)
|
||||
@@ -365,7 +365,7 @@ struct ContentDetailView: View {
|
||||
}
|
||||
},
|
||||
showToast: {
|
||||
viewModel.errorMessage = "동의하셔야 삭제할 수 있습니다."
|
||||
viewModel.errorMessage = I18n.ContentDetail.deleteAgreementRequired
|
||||
viewModel.isShowPopup = true
|
||||
}
|
||||
)
|
||||
|
||||
@@ -69,14 +69,14 @@ final class ContentDetailViewModel: ObservableObject {
|
||||
if let message = decoded.message {
|
||||
self.errorMessage = message
|
||||
} else {
|
||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
||||
self.errorMessage = I18n.Common.commonError
|
||||
}
|
||||
|
||||
self.isShowPopup = true
|
||||
}
|
||||
} catch {
|
||||
print(error)
|
||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
||||
self.errorMessage = I18n.Common.commonError
|
||||
self.isShowPopup = true
|
||||
}
|
||||
|
||||
@@ -110,13 +110,13 @@ final class ContentDetailViewModel: ObservableObject {
|
||||
if let message = decoded.message {
|
||||
self.errorMessage = message
|
||||
} else {
|
||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
||||
self.errorMessage = I18n.Common.commonError
|
||||
}
|
||||
|
||||
self.isShowPopup = true
|
||||
}
|
||||
} catch {
|
||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
||||
self.errorMessage = I18n.Common.commonError
|
||||
self.isShowPopup = true
|
||||
}
|
||||
}
|
||||
@@ -148,13 +148,13 @@ final class ContentDetailViewModel: ObservableObject {
|
||||
if let message = decoded.message {
|
||||
self.errorMessage = message
|
||||
} else {
|
||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
||||
self.errorMessage = I18n.Common.commonError
|
||||
}
|
||||
|
||||
self.isShowPopup = true
|
||||
}
|
||||
} catch {
|
||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
||||
self.errorMessage = I18n.Common.commonError
|
||||
self.isShowPopup = true
|
||||
}
|
||||
}
|
||||
@@ -186,13 +186,13 @@ final class ContentDetailViewModel: ObservableObject {
|
||||
if let message = decoded.message {
|
||||
self.errorMessage = message
|
||||
} else {
|
||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
||||
self.errorMessage = I18n.Common.commonError
|
||||
}
|
||||
|
||||
self.isShowPopup = true
|
||||
}
|
||||
} catch {
|
||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
||||
self.errorMessage = I18n.Common.commonError
|
||||
self.isShowPopup = true
|
||||
}
|
||||
}
|
||||
@@ -212,7 +212,7 @@ final class ContentDetailViewModel: ObservableObject {
|
||||
self.shareMessage = shareUrl
|
||||
self.isShowShareView = true
|
||||
} else {
|
||||
self.errorMessage = "공유링크를 생성하지 못했습니다.\n다시 시도해 주세요."
|
||||
self.errorMessage = I18n.ContentDetail.shareLinkCreateFailed
|
||||
self.isShowPopup = true
|
||||
}
|
||||
|
||||
@@ -248,13 +248,13 @@ final class ContentDetailViewModel: ObservableObject {
|
||||
if let message = decoded.message {
|
||||
self.errorMessage = message
|
||||
} else {
|
||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
||||
self.errorMessage = I18n.Common.commonError
|
||||
}
|
||||
|
||||
self.isShowPopup = true
|
||||
}
|
||||
} catch {
|
||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
||||
self.errorMessage = I18n.Common.commonError
|
||||
self.isShowPopup = true
|
||||
}
|
||||
}
|
||||
@@ -286,26 +286,26 @@ final class ContentDetailViewModel: ObservableObject {
|
||||
AppState.shared.purchasedContentOrderType = .KEEP
|
||||
|
||||
self.orderType = nil
|
||||
self.errorMessage = orderType == .RENTAL ? "대여가 완료되었습니다." : "구매가 완료되었습니다."
|
||||
self.errorMessage = orderType == .RENTAL ? I18n.ContentDetail.rentalCompleted : I18n.ContentDetail.purchaseCompleted
|
||||
self.isShowPopup = true
|
||||
self.getAudioContentDetail()
|
||||
ContentPlayManager.shared.conditionalStopAudio(contentId: contentId)
|
||||
} else {
|
||||
if let message = decoded.message {
|
||||
self.errorMessage = message
|
||||
if message.contains("캔이 부족합니다") {
|
||||
if isInsufficientCanError(message: message, errorProperty: decoded.errorProperty) {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
|
||||
AppState.shared.setAppStep(step: .canCharge(refresh: {}, afterCompletionToGoBack: true))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
||||
self.errorMessage = I18n.Common.commonError
|
||||
}
|
||||
|
||||
self.isShowPopup = true
|
||||
}
|
||||
} catch {
|
||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
||||
self.errorMessage = I18n.Common.commonError
|
||||
self.isShowPopup = true
|
||||
}
|
||||
}
|
||||
@@ -335,12 +335,12 @@ final class ContentDetailViewModel: ObservableObject {
|
||||
if let message = decoded.message {
|
||||
self.errorMessage = message
|
||||
} else {
|
||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
||||
self.errorMessage = I18n.Common.commonError
|
||||
}
|
||||
|
||||
self.isShowPopup = true
|
||||
} catch {
|
||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
||||
self.errorMessage = I18n.Common.commonError
|
||||
self.isShowPopup = true
|
||||
}
|
||||
}
|
||||
@@ -368,20 +368,20 @@ final class ContentDetailViewModel: ObservableObject {
|
||||
|
||||
if decoded.success {
|
||||
self.orderType = nil
|
||||
self.errorMessage = "삭제되었습니다"
|
||||
self.errorMessage = I18n.ContentDetail.deleteCompleted
|
||||
self.isShowPopup = true
|
||||
onSuccess()
|
||||
} else {
|
||||
if let message = decoded.message {
|
||||
self.errorMessage = message
|
||||
} else {
|
||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
||||
self.errorMessage = I18n.Common.commonError
|
||||
}
|
||||
|
||||
self.isShowPopup = true
|
||||
}
|
||||
} catch {
|
||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
||||
self.errorMessage = I18n.Common.commonError
|
||||
self.isShowPopup = true
|
||||
}
|
||||
}
|
||||
@@ -390,10 +390,10 @@ final class ContentDetailViewModel: ObservableObject {
|
||||
|
||||
func donation(can: Int, comment: String) {
|
||||
if can <= 0 {
|
||||
self.errorMessage = "1캔 이상 후원하실 수 있습니다."
|
||||
self.errorMessage = I18n.LiveRoom.atLeastOneCanDonationMessage
|
||||
self.isShowPopup = true
|
||||
} else if comment.trimmingCharacters(in: .whitespaces).isEmpty {
|
||||
self.errorMessage = "함께 보낼 메시지를 입력하세요."
|
||||
self.errorMessage = I18n.ContentDetail.donationMessageRequired
|
||||
self.isShowPopup = true
|
||||
} else {
|
||||
isLoading = true
|
||||
@@ -415,7 +415,7 @@ final class ContentDetailViewModel: ObservableObject {
|
||||
|
||||
if decoded.success {
|
||||
UserDefaults.set(UserDefaults.int(forKey: .can) - can, forKey: .can)
|
||||
self.errorMessage = "\(can)캔을 후원하셨습니다."
|
||||
self.errorMessage = I18n.ContentDetail.donationCompleted(can)
|
||||
self.isShowPopup = true
|
||||
|
||||
self.getAudioContentDetail()
|
||||
@@ -423,13 +423,13 @@ final class ContentDetailViewModel: ObservableObject {
|
||||
if let message = decoded.message {
|
||||
self.errorMessage = message
|
||||
} else {
|
||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
||||
self.errorMessage = I18n.Common.commonError
|
||||
}
|
||||
|
||||
self.isShowPopup = true
|
||||
}
|
||||
} catch {
|
||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
||||
self.errorMessage = I18n.Common.commonError
|
||||
self.isShowPopup = true
|
||||
}
|
||||
}
|
||||
@@ -456,7 +456,7 @@ final class ContentDetailViewModel: ObservableObject {
|
||||
let decoded = try jsonDecoder.decode(ApiResponseWithoutData.self, from: responseData)
|
||||
|
||||
if decoded.success {
|
||||
self.errorMessage = "고정되었습니다"
|
||||
self.errorMessage = I18n.ContentDetail.pinCompleted
|
||||
self.isShowPopup = true
|
||||
|
||||
self.getAudioContentDetail()
|
||||
@@ -464,13 +464,13 @@ final class ContentDetailViewModel: ObservableObject {
|
||||
if let message = decoded.message {
|
||||
self.errorMessage = message
|
||||
} else {
|
||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
||||
self.errorMessage = I18n.Common.commonError
|
||||
}
|
||||
|
||||
self.isShowPopup = true
|
||||
}
|
||||
} catch {
|
||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
||||
self.errorMessage = I18n.Common.commonError
|
||||
self.isShowPopup = true
|
||||
}
|
||||
}
|
||||
@@ -496,7 +496,7 @@ final class ContentDetailViewModel: ObservableObject {
|
||||
let decoded = try jsonDecoder.decode(ApiResponseWithoutData.self, from: responseData)
|
||||
|
||||
if decoded.success {
|
||||
self.errorMessage = "해제되었습니다"
|
||||
self.errorMessage = I18n.ContentDetail.unpinCompleted
|
||||
self.isShowPopup = true
|
||||
|
||||
self.getAudioContentDetail()
|
||||
@@ -504,16 +504,40 @@ final class ContentDetailViewModel: ObservableObject {
|
||||
if let message = decoded.message {
|
||||
self.errorMessage = message
|
||||
} else {
|
||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
||||
self.errorMessage = I18n.Common.commonError
|
||||
}
|
||||
|
||||
self.isShowPopup = true
|
||||
}
|
||||
} catch {
|
||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
||||
self.errorMessage = I18n.Common.commonError
|
||||
self.isShowPopup = true
|
||||
}
|
||||
}
|
||||
.store(in: &subscription)
|
||||
}
|
||||
|
||||
private func isInsufficientCanError(message: String, errorProperty: String?) -> Bool {
|
||||
let normalizedErrorProperty = errorProperty?.lowercased() ?? ""
|
||||
|
||||
if normalizedErrorProperty.contains("not_enough_can") ||
|
||||
normalizedErrorProperty.contains("insufficient_can") ||
|
||||
normalizedErrorProperty.contains("lack_of_can")
|
||||
{
|
||||
return true
|
||||
}
|
||||
|
||||
let normalizedMessage = message.lowercased()
|
||||
let insufficientCanPatterns = [
|
||||
"캔이 부족",
|
||||
"캔 부족",
|
||||
"not enough can",
|
||||
"insufficient can",
|
||||
"not enough cans",
|
||||
"insufficient cans",
|
||||
"canが不足"
|
||||
]
|
||||
|
||||
return insufficientCanPatterns.contains { normalizedMessage.contains($0) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ struct ContentOrderConfirmDialogView: View {
|
||||
.ignoresSafeArea()
|
||||
|
||||
VStack(spacing: 0) {
|
||||
Text("구매확인")
|
||||
Text(I18n.ContentDetail.OrderConfirmDialog.title)
|
||||
.appFont(size: 18.3, weight: .bold)
|
||||
.foregroundColor(Color.grayee)
|
||||
|
||||
@@ -100,7 +100,11 @@ struct ContentOrderConfirmDialogView: View {
|
||||
.cornerRadius(5.3)
|
||||
.padding(.top, 21.3)
|
||||
|
||||
Text("콘텐츠를 \(orderType == .RENTAL ? "대여" : "소장")하시겠습니까?")
|
||||
Text(
|
||||
orderType == .RENTAL ?
|
||||
I18n.ContentDetail.OrderConfirmDialog.rentQuestion :
|
||||
I18n.ContentDetail.OrderConfirmDialog.buyQuestion
|
||||
)
|
||||
.appFont(size: 13.3, weight: .medium)
|
||||
.foregroundColor(Color.grayee)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
@@ -108,7 +112,7 @@ struct ContentOrderConfirmDialogView: View {
|
||||
.padding(.top, 13.3)
|
||||
|
||||
if UserDefaults.int(forKey: .userId) != 17958 {
|
||||
Text("아래 금액이 차감됩니다.")
|
||||
Text(I18n.ContentDetail.OrderConfirmDialog.deductionNotice)
|
||||
.appFont(size: 13.3, weight: .medium)
|
||||
.foregroundColor(Color.grayee)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
@@ -150,7 +154,7 @@ struct ContentOrderConfirmDialogView: View {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Text("\(price * 110)원")
|
||||
Text("\(price * 110)\(I18n.ContentDetail.Purchase.wonUnit)")
|
||||
.appFont(size: 13.3, weight: .bold)
|
||||
.foregroundColor(Color.grayee)
|
||||
}
|
||||
@@ -168,7 +172,7 @@ struct ContentOrderConfirmDialogView: View {
|
||||
.padding(.top, 13.3)
|
||||
|
||||
HStack(spacing: 12) {
|
||||
Text("취소")
|
||||
Text(I18n.Common.cancel)
|
||||
.appFont(size: 18.3, weight: .bold)
|
||||
.foregroundColor(Color.button)
|
||||
.padding(.vertical, 15.7)
|
||||
@@ -181,7 +185,7 @@ struct ContentOrderConfirmDialogView: View {
|
||||
)
|
||||
.onTapGesture { isShowing = false }
|
||||
|
||||
Text("확인")
|
||||
Text(I18n.Common.confirm)
|
||||
.appFont(size: 18.3, weight: .bold)
|
||||
.foregroundColor(.white)
|
||||
.padding(.vertical, 15.7)
|
||||
|
||||
@@ -27,11 +27,11 @@ struct ContentOrderDialogView: View {
|
||||
VStack(spacing: 26.7) {
|
||||
HStack(spacing: 0) {
|
||||
VStack(alignment: .leading, spacing: 5.3) {
|
||||
Text("대여")
|
||||
Text(I18n.ContentDetail.OrderDialog.rent)
|
||||
.appFont(size: 13.3, weight: .bold)
|
||||
.foregroundColor(.white)
|
||||
|
||||
Text("(이용기간 5일)")
|
||||
Text(I18n.ContentDetail.OrderDialog.rentPeriod)
|
||||
.appFont(size: 12, weight: .light)
|
||||
.foregroundColor(.white)
|
||||
}
|
||||
@@ -56,7 +56,7 @@ struct ContentOrderDialogView: View {
|
||||
}
|
||||
|
||||
if UserDefaults.int(forKey: .userId) == 17958 {
|
||||
Text("원")
|
||||
Text(I18n.ContentDetail.Purchase.wonUnit)
|
||||
.appFont(size: 13.3, weight: .bold)
|
||||
.foregroundColor(Color.grayee)
|
||||
}
|
||||
@@ -73,11 +73,11 @@ struct ContentOrderDialogView: View {
|
||||
|
||||
HStack(spacing: 0) {
|
||||
VStack(alignment: .leading, spacing: 5.3) {
|
||||
Text("소장")
|
||||
Text(I18n.ContentDetail.OrderDialog.buy)
|
||||
.appFont(size: 13.3, weight: .bold)
|
||||
.foregroundColor(.white)
|
||||
|
||||
Text("(서비스 종료시까지)")
|
||||
Text(I18n.ContentDetail.OrderDialog.buyPeriod)
|
||||
.appFont(size: 12, weight: .light)
|
||||
.foregroundColor(.white)
|
||||
}
|
||||
@@ -102,7 +102,7 @@ struct ContentOrderDialogView: View {
|
||||
}
|
||||
|
||||
if UserDefaults.int(forKey: .userId) == 17958 {
|
||||
Text("원")
|
||||
Text(I18n.ContentDetail.Purchase.wonUnit)
|
||||
.appFont(size: 13.3, weight: .bold)
|
||||
.foregroundColor(Color.grayee)
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ struct LiveRoomDonationDialogView: View {
|
||||
.resizable()
|
||||
.frame(width: 26.7, height: 26.7)
|
||||
|
||||
Text("후원하기")
|
||||
Text(I18n.ContentDetail.DonationDialog.title)
|
||||
.appFont(size: 18.3, weight: .bold)
|
||||
.foregroundColor(Color.grayee)
|
||||
|
||||
@@ -80,7 +80,7 @@ struct LiveRoomDonationDialogView: View {
|
||||
.appFont(size: 18.3, weight: .bold)
|
||||
.foregroundColor(Color.grayee)
|
||||
|
||||
Text("충전")
|
||||
Text(I18n.ContentDetail.DonationDialog.charge)
|
||||
.appFont(size: 13.3, weight: .medium)
|
||||
.foregroundColor(Color.main)
|
||||
.padding(.horizontal, 13.3)
|
||||
@@ -126,7 +126,12 @@ struct LiveRoomDonationDialogView: View {
|
||||
.padding(.top, 16)
|
||||
}
|
||||
|
||||
TextField(isSecret ? "10캔 이상 입력하세요" : "1캔 이상 입력하세요", text: $donationCan)
|
||||
TextField(
|
||||
isSecret ?
|
||||
I18n.ContentDetail.DonationDialog.minimumTenCanPlaceholder :
|
||||
I18n.ContentDetail.DonationDialog.minimumOneCanPlaceholder,
|
||||
text: $donationCan
|
||||
)
|
||||
.appFont(size: 13.3, weight: .medium)
|
||||
.foregroundColor(Color.grayee)
|
||||
.padding(13.3)
|
||||
@@ -227,7 +232,10 @@ struct LiveRoomDonationDialogView: View {
|
||||
)
|
||||
|
||||
TextField(
|
||||
"함께 보낼 \((isSecret && shouldPrefixSecretInMessagePlaceholder) ? "비밀 " : "")메시지 입력(최대 \(messageLimit)자)",
|
||||
I18n.ContentDetail.DonationDialog.messagePlaceholder(
|
||||
isSecret: isSecret && shouldPrefixSecretInMessagePlaceholder,
|
||||
limit: messageLimit
|
||||
),
|
||||
text: $donationMessage
|
||||
)
|
||||
.appFont(size: 13.3, weight: .medium)
|
||||
@@ -242,7 +250,7 @@ struct LiveRoomDonationDialogView: View {
|
||||
.padding(.horizontal, 20)
|
||||
|
||||
HStack(spacing: 13.3) {
|
||||
Text("취소")
|
||||
Text(I18n.Common.cancel)
|
||||
.appFont(size: 15, weight: .bold)
|
||||
.foregroundColor(Color.button)
|
||||
.padding(.vertical, 16)
|
||||
@@ -258,7 +266,7 @@ struct LiveRoomDonationDialogView: View {
|
||||
isShowing = false
|
||||
}
|
||||
|
||||
Text("후원하기")
|
||||
Text(I18n.ContentDetail.DonationDialog.donateAction)
|
||||
.appFont(size: 15, weight: .bold)
|
||||
.foregroundColor(.white)
|
||||
.padding(.vertical, 16)
|
||||
@@ -271,14 +279,14 @@ struct LiveRoomDonationDialogView: View {
|
||||
errorMessage = secretMinimumCanMessage
|
||||
isShowErrorPopup = true
|
||||
} else if can < 1 {
|
||||
errorMessage = "1캔 이상 후원하실 수 있습니다."
|
||||
errorMessage = I18n.LiveRoom.atLeastOneCanDonationMessage
|
||||
isShowErrorPopup = true
|
||||
} else {
|
||||
onClickDonation(can, donationMessage, isSecret)
|
||||
isShowing = false
|
||||
}
|
||||
} else {
|
||||
errorMessage = "1캔 이상 후원하실 수 있습니다."
|
||||
errorMessage = I18n.LiveRoom.atLeastOneCanDonationMessage
|
||||
isShowErrorPopup = true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,13 +49,13 @@ final class ContentMainBannerViewModel: ObservableObject {
|
||||
if let message = decoded.message {
|
||||
self.errorMessage = message
|
||||
} else {
|
||||
self.errorMessage = "배너를 불러오지 못했습니다. 다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
||||
self.errorMessage = I18n.Content.Banner.loadFailed
|
||||
}
|
||||
|
||||
self.isShowPopup = true
|
||||
}
|
||||
} catch {
|
||||
self.errorMessage = "배너를 불러오지 못했습니다. 다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
||||
self.errorMessage = I18n.Content.Banner.loadFailed
|
||||
self.isShowPopup = true
|
||||
self.isLoading = false
|
||||
}
|
||||
|
||||
@@ -21,11 +21,11 @@ struct ContentModifyView: View {
|
||||
GeometryReader { proxy in
|
||||
ZStack {
|
||||
VStack(spacing: 0) {
|
||||
DetailNavigationBar(title: "콘텐츠 수정")
|
||||
DetailNavigationBar(title: I18n.CreateContent.modifyTitle)
|
||||
|
||||
ScrollView(.vertical, showsIndicators: false) {
|
||||
VStack(spacing: 0) {
|
||||
Text("썸네일")
|
||||
Text(I18n.CreateContent.thumbnail)
|
||||
.appFont(size: 16.7, weight: .bold)
|
||||
.foregroundColor(Color(hex: "eeeeee"))
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
@@ -82,12 +82,12 @@ struct ContentModifyView: View {
|
||||
.padding(.top, 26.7)
|
||||
|
||||
VStack(spacing: 0) {
|
||||
Text("제목")
|
||||
Text(I18n.CreateContent.titleLabel)
|
||||
.appFont(size: 16.7, weight: .bold)
|
||||
.foregroundColor(Color(hex: "eeeeee"))
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
|
||||
TextField("제목을 입력하세요", text: $viewModel.title)
|
||||
TextField(I18n.CreateContent.titlePlaceholder, text: $viewModel.title)
|
||||
.autocapitalization(.none)
|
||||
.disableAutocorrection(true)
|
||||
.appFont(size: 13.3, weight: .medium)
|
||||
@@ -100,16 +100,16 @@ struct ContentModifyView: View {
|
||||
.padding(.top, 13.3)
|
||||
|
||||
HStack(spacing: 0) {
|
||||
Text("내용")
|
||||
Text(I18n.CreateContent.contentLabel)
|
||||
.appFont(size: 16.7, weight: .bold)
|
||||
.foregroundColor(Color(hex: "eeeeee"))
|
||||
|
||||
Spacer()
|
||||
|
||||
Text("\(viewModel.detail.count)자")
|
||||
Text(I18n.CreateContent.characterCount(viewModel.detail.count))
|
||||
.appFont(size: 13.3, weight: .medium)
|
||||
.foregroundColor(Color(hex: "ff5c49"))
|
||||
Text(" / 최대 500자")
|
||||
Text(I18n.CreateContent.max500CharactersSuffix)
|
||||
.appFont(size: 13.3, weight: .medium)
|
||||
.foregroundColor(Color(hex: "777777"))
|
||||
}
|
||||
@@ -125,13 +125,13 @@ struct ContentModifyView: View {
|
||||
.cornerRadius(6.7)
|
||||
.padding(.top, 13.3)
|
||||
|
||||
Text("태그")
|
||||
Text(I18n.CreateContent.tagLabel)
|
||||
.appFont(size: 16.7, weight: .bold)
|
||||
.foregroundColor(Color.grayee)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.padding(.top, 26.7)
|
||||
|
||||
TextField("예: #연애 #커버곡", text: $viewModel.hashtags)
|
||||
TextField(I18n.CreateContent.tagPlaceholderExample, text: $viewModel.hashtags)
|
||||
.autocapitalization(.none)
|
||||
.disableAutocorrection(true)
|
||||
.appFont(size: 13.3, weight: .medium)
|
||||
@@ -152,19 +152,19 @@ struct ContentModifyView: View {
|
||||
.padding(.top, 26.7)
|
||||
|
||||
VStack(spacing: 13.3) {
|
||||
Text("포인트 사용")
|
||||
Text(I18n.CreateContent.pointUsageTitle)
|
||||
.appFont(size: 16.7, weight: .bold)
|
||||
.foregroundColor(Color.grayee)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
|
||||
HStack(spacing: 13.3) {
|
||||
SelectButtonView(title: "가능", isChecked: viewModel.isPointAvailable) {
|
||||
SelectButtonView(title: I18n.CreateContent.available, isChecked: viewModel.isPointAvailable) {
|
||||
if !viewModel.isPointAvailable {
|
||||
viewModel.isPointAvailable = true
|
||||
}
|
||||
}
|
||||
|
||||
SelectButtonView(title: "불가능", isChecked: !viewModel.isPointAvailable) {
|
||||
SelectButtonView(title: I18n.CreateContent.unavailable, isChecked: !viewModel.isPointAvailable) {
|
||||
if viewModel.isPointAvailable {
|
||||
viewModel.isPointAvailable = false
|
||||
}
|
||||
@@ -176,26 +176,26 @@ struct ContentModifyView: View {
|
||||
|
||||
if viewModel.isAdultShowUi {
|
||||
VStack(spacing: 13.3) {
|
||||
Text("연령 제한")
|
||||
Text(I18n.CreateContent.ageRestrictionTitle)
|
||||
.appFont(size: 16.7, weight: .bold)
|
||||
.foregroundColor(Color(hex: "eeeeee"))
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
|
||||
HStack(spacing: 13.3) {
|
||||
SelectButtonView(title: "전체 연령", isChecked: !viewModel.isAdult) {
|
||||
SelectButtonView(title: I18n.CreateContent.allAges, isChecked: !viewModel.isAdult) {
|
||||
if viewModel.isAdult {
|
||||
viewModel.isAdult = false
|
||||
}
|
||||
}
|
||||
|
||||
SelectButtonView(title: "19세 이상", isChecked: viewModel.isAdult) {
|
||||
SelectButtonView(title: I18n.CreateContent.over19, isChecked: viewModel.isAdult) {
|
||||
if !viewModel.isAdult {
|
||||
viewModel.isAdult = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Text("성인콘텐츠를 전체관람가로 등록할 시 발생하는 법적 책임은 회사와 상관없이 콘텐츠를 등록한 본인에게 있습니다.\n콘텐츠 내용은 물론 제목도 19금 여부를 체크해 주시기 바랍니다.")
|
||||
Text(I18n.CreateContent.adultLegalNotice)
|
||||
.appFont(size: 13.3, weight: .medium)
|
||||
.foregroundColor(Color(hex: "DD4500"))
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
@@ -206,19 +206,19 @@ struct ContentModifyView: View {
|
||||
}
|
||||
|
||||
VStack(spacing: 13.3) {
|
||||
Text("댓글 가능 여부")
|
||||
Text(I18n.CreateContent.commentAvailabilityTitle)
|
||||
.appFont(size: 16.7, weight: .bold)
|
||||
.foregroundColor(Color(hex: "eeeeee"))
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
|
||||
HStack(spacing: 13.3) {
|
||||
SelectButtonView(title: "댓글 가능", isChecked: viewModel.isAvailableComment) {
|
||||
SelectButtonView(title: I18n.CreateContent.commentAllowed, isChecked: viewModel.isAvailableComment) {
|
||||
if !viewModel.isAvailableComment {
|
||||
viewModel.isAvailableComment = true
|
||||
}
|
||||
}
|
||||
|
||||
SelectButtonView(title: "댓글 불가", isChecked: !viewModel.isAvailableComment) {
|
||||
SelectButtonView(title: I18n.CreateContent.commentNotAllowed, isChecked: !viewModel.isAvailableComment) {
|
||||
if viewModel.isAvailableComment {
|
||||
viewModel.isAvailableComment = false
|
||||
}
|
||||
@@ -230,7 +230,7 @@ struct ContentModifyView: View {
|
||||
|
||||
VStack(spacing: 0) {
|
||||
HStack(alignment: .top, spacing: 0) {
|
||||
Text("수정")
|
||||
Text(I18n.CreateContent.modifyAction)
|
||||
.appFont(size: 18.3, weight: .bold)
|
||||
.foregroundColor(Color.white)
|
||||
.frame(height: 50)
|
||||
|
||||
@@ -31,7 +31,7 @@ final class ContentModifyViewModel: ObservableObject {
|
||||
@Published var isAdultShowUi = false
|
||||
|
||||
var contentId: Int = 0
|
||||
var placeholder = "내용을 입력하세요"
|
||||
var placeholder = I18n.CreateContent.uploadContentDescriptionHint
|
||||
|
||||
func getAudioContentDetail(onFailure: (() -> Void)? = nil) {
|
||||
audioContent = nil
|
||||
@@ -68,13 +68,13 @@ final class ContentModifyViewModel: ObservableObject {
|
||||
if let message = decoded.message {
|
||||
self.errorMessage = message
|
||||
} else {
|
||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
||||
self.errorMessage = I18n.Common.commonError
|
||||
}
|
||||
|
||||
self.isShowPopup = true
|
||||
}
|
||||
} catch {
|
||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
||||
self.errorMessage = I18n.Common.commonError
|
||||
self.isShowPopup = true
|
||||
}
|
||||
}
|
||||
@@ -112,7 +112,7 @@ final class ContentModifyViewModel: ObservableObject {
|
||||
mimeType: "image/*")
|
||||
)
|
||||
} else {
|
||||
errorMessage = "커버이미지를 업로드 하지 못했습니다.\n다시 선택해 주세요"
|
||||
errorMessage = I18n.CreateContent.coverImageUploadFailed
|
||||
isShowPopup = true
|
||||
isLoading = false
|
||||
return
|
||||
@@ -139,26 +139,26 @@ final class ContentModifyViewModel: ObservableObject {
|
||||
let decoded = try jsonDecoder.decode(ApiResponseWithoutData.self, from: responseData)
|
||||
|
||||
if decoded.success {
|
||||
self.errorMessage = "콘텐츠가 수정되었습니다."
|
||||
self.errorMessage = I18n.CreateContent.modifySuccess
|
||||
self.isShowPopup = true
|
||||
onSuccess()
|
||||
} else {
|
||||
if let message = decoded.message {
|
||||
self.errorMessage = message
|
||||
} else {
|
||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
||||
self.errorMessage = I18n.Common.commonError
|
||||
}
|
||||
|
||||
self.isShowPopup = true
|
||||
}
|
||||
} catch {
|
||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
||||
self.errorMessage = I18n.Common.commonError
|
||||
self.isShowPopup = true
|
||||
}
|
||||
}
|
||||
.store(in: &subscription)
|
||||
} else {
|
||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
||||
self.errorMessage = I18n.Common.commonError
|
||||
self.isShowPopup = true
|
||||
self.isLoading = false
|
||||
}
|
||||
@@ -167,13 +167,13 @@ final class ContentModifyViewModel: ObservableObject {
|
||||
|
||||
private func validateData() -> Bool {
|
||||
if title != audioContent!.title && title.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
|
||||
errorMessage = "제목을 입력해 주세요."
|
||||
errorMessage = I18n.CreateContent.titleRequired
|
||||
isShowPopup = true
|
||||
return false
|
||||
}
|
||||
|
||||
if detail != audioContent!.detail && (detail.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty || detail.count < 5) {
|
||||
errorMessage = "내용을 5자 이상 입력해 주세요."
|
||||
errorMessage = I18n.CreateContent.detailMinLengthRequired
|
||||
isShowPopup = true
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ struct ContentPlaylistItemView: View {
|
||||
.lineLimit(1)
|
||||
}
|
||||
|
||||
Text("총 \(item.contentCount)개")
|
||||
Text(I18n.Content.Playlist.itemCount(item.contentCount))
|
||||
.appFont(size: 12, weight: .medium)
|
||||
.foregroundColor(Color.gray90)
|
||||
.lineLimit(1)
|
||||
|
||||
@@ -17,7 +17,7 @@ struct ContentPlaylistListView: View {
|
||||
var body: some View {
|
||||
BaseView(isLoading: $viewModel.isLoading) {
|
||||
VStack(spacing: 13.3) {
|
||||
Text("+ 새 재생목록 만들기")
|
||||
Text(I18n.Content.Playlist.createNewAction)
|
||||
.appFont(size: 14.7, weight: .bold)
|
||||
.foregroundColor(Color.white)
|
||||
.padding(.vertical, 13.3)
|
||||
@@ -31,11 +31,11 @@ struct ContentPlaylistListView: View {
|
||||
|
||||
if viewModel.playlists.isEmpty {
|
||||
VStack(spacing: 13.3) {
|
||||
Text("재생목록이 비어있습니다.")
|
||||
Text(I18n.Content.Playlist.emptyTitle)
|
||||
.appFont(size: 14.7, weight: .bold)
|
||||
.foregroundColor(Color.grayee)
|
||||
|
||||
Text("자주 듣는 콘텐츠를\n재생목록으로 만들어 보세요.")
|
||||
Text(I18n.Content.Playlist.emptyDescription)
|
||||
.appFont(size: 11, weight: .medium)
|
||||
.foregroundColor(Color.grayee)
|
||||
.multilineTextAlignment(.center)
|
||||
@@ -45,11 +45,11 @@ struct ContentPlaylistListView: View {
|
||||
.cornerRadius(4.7)
|
||||
} else {
|
||||
HStack(spacing: 5.3) {
|
||||
Text("전체")
|
||||
Text(I18n.Content.Playlist.totalLabel)
|
||||
.appFont(size: 14.7, weight: .medium)
|
||||
.foregroundColor(Color.white)
|
||||
|
||||
Text("\(viewModel.totalCount)개")
|
||||
Text("\(viewModel.totalCount)\(I18n.Content.Count.countUnit)")
|
||||
.appFont(size: 12, weight: .medium)
|
||||
.foregroundColor(Color.gray90)
|
||||
|
||||
|
||||
@@ -41,18 +41,18 @@ final class ContentPlaylistListViewModel: ObservableObject {
|
||||
self.totalCount = data.totalCount
|
||||
self.playlists.append(contentsOf: data.items)
|
||||
} else {
|
||||
if let message = decoded.message {
|
||||
self.errorMessage = message
|
||||
} else {
|
||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
||||
}
|
||||
if let message = decoded.message {
|
||||
self.errorMessage = message
|
||||
} else {
|
||||
self.errorMessage = I18n.Common.commonError
|
||||
}
|
||||
|
||||
self.isShowPopup = true
|
||||
}
|
||||
} catch {
|
||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
||||
self.isShowPopup = true
|
||||
}
|
||||
} catch {
|
||||
self.errorMessage = I18n.Common.commonError
|
||||
self.isShowPopup = true
|
||||
}
|
||||
|
||||
self.isLoading = false
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user