콘텐츠 등록 화면 텍스트와 버튼을 I18n 기반 번역 문자열로 교체 룰렛 설정과 미션 메뉴 버튼 라벨을 다국어 문자열로 통일 신규 텍스트를 String Catalog에 추가하여 네비게이션 타이틀 번역
337 lines
12 KiB
Swift
337 lines
12 KiB
Swift
//
|
|
// ContentCreateViewModel.swift
|
|
// SodaLive
|
|
//
|
|
// Created by klaus on 2023/08/11.
|
|
//
|
|
|
|
import UIKit
|
|
import Moya
|
|
import Combine
|
|
|
|
final class ContentCreateViewModel: ObservableObject {
|
|
|
|
private let repository = ContentRepository()
|
|
private var subscription = Set<AnyCancellable>()
|
|
|
|
@Published var isLoading = false
|
|
@Published var isShowCompletePopup = false
|
|
@Published var errorMessage = ""
|
|
@Published var isShowPopup = false
|
|
@Published var fileName = ""
|
|
|
|
@Published var title = ""
|
|
@Published var detail = ""
|
|
@Published var hashtags: String = ""
|
|
@Published var theme: GetAudioContentThemeResponse? = nil
|
|
@Published var coverImage: UIImage? = nil
|
|
@Published var selectedFileUrl: URL? = nil {
|
|
didSet {
|
|
if let fileUrl = selectedFileUrl {
|
|
fileName = fileUrl.lastPathComponent
|
|
}
|
|
}
|
|
}
|
|
|
|
@Published var isAvailableComment = true
|
|
@Published var isActiveReservation = false
|
|
@Published var isAdult = false
|
|
@Published var priceString = "0" {
|
|
didSet {
|
|
if priceString.count > 5 {
|
|
priceString = String(priceString.prefix(5))
|
|
} else {
|
|
if let price = Int(priceString) {
|
|
self.price = price
|
|
} else {
|
|
self.price = 0
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@Published var price = 0
|
|
|
|
@Published var isFree = true {
|
|
didSet {
|
|
if isFree {
|
|
priceString = "0"
|
|
isLimited = false
|
|
isGeneratePreview = true
|
|
isPointAvailable = false
|
|
purchaseOption = PurchaseOption.BOTH
|
|
}
|
|
}
|
|
}
|
|
|
|
@Published var purchaseOption = PurchaseOption.BOTH {
|
|
didSet {
|
|
if purchaseOption == .RENT_ONLY {
|
|
isLimited = false
|
|
}
|
|
}
|
|
}
|
|
@Published var isGeneratePreview = true
|
|
@Published var isPointAvailable = false
|
|
|
|
@Published var isLimited = false {
|
|
didSet {
|
|
if !isLimited {
|
|
limitedString = ""
|
|
}
|
|
}
|
|
}
|
|
|
|
@Published var limited: Int? = nil {
|
|
didSet {
|
|
if let limited = limited, limited <= 0 {
|
|
limitedString = ""
|
|
}
|
|
}
|
|
}
|
|
|
|
@Published var limitedString: String = "" {
|
|
didSet {
|
|
if limitedString == "" {
|
|
limited = nil
|
|
} else {
|
|
limited = Int(limitedString)
|
|
}
|
|
}
|
|
}
|
|
|
|
@Published var previewStartTime: String = ""
|
|
@Published var previewEndTime: String = ""
|
|
@Published var releaseDateString: String = Date().convertDateFormat(dateFormat: "yyyy.MM.dd")
|
|
@Published var releaseTimeString: String = Date().convertDateFormat(dateFormat: "a hh:mm")
|
|
|
|
var releaseDate = Date() {
|
|
willSet {
|
|
releaseDateString = newValue.convertDateFormat(dateFormat: "yyyy.MM.dd")
|
|
}
|
|
}
|
|
|
|
var releaseTime = Date() {
|
|
willSet {
|
|
releaseTimeString = newValue.convertDateFormat(dateFormat: "a hh:mm")
|
|
}
|
|
}
|
|
|
|
func uploadAudioContent() {
|
|
if !isLoading && validateData() {
|
|
isLoading = true
|
|
|
|
let request = CreateAudioContentRequest(
|
|
title: title,
|
|
detail: detail,
|
|
tags: hashtags,
|
|
price: price,
|
|
purchaseOption: purchaseOption,
|
|
limited: limited,
|
|
releaseDate: isActiveReservation ? "\(releaseDate.convertDateFormat(dateFormat: "yyyy-MM-dd")) \(releaseTime.convertDateFormat(dateFormat: "HH:mm"))" : nil,
|
|
timezone: TimeZone.current.identifier,
|
|
themeId: theme!.id,
|
|
isAdult: isAdult,
|
|
isGeneratePreview: isGeneratePreview,
|
|
isPointAvailable: isPointAvailable,
|
|
isCommentAvailable: isAvailableComment,
|
|
previewStartTime: isGeneratePreview && previewStartTime.trimmingCharacters(in: .whitespacesAndNewlines).count > 0 ? previewStartTime : nil,
|
|
previewEndTime: isGeneratePreview && previewEndTime.trimmingCharacters(in: .whitespacesAndNewlines).count > 0 ? previewEndTime : nil
|
|
)
|
|
|
|
var multipartData = [MultipartFormData]()
|
|
|
|
let encoder = JSONEncoder()
|
|
encoder.outputFormatting = .withoutEscapingSlashes
|
|
let jsonData = try? encoder.encode(request)
|
|
|
|
if let jsonData = jsonData {
|
|
if let coverImage = coverImage, let imageData = coverImage.jpegData(compressionQuality: 0.8) {
|
|
multipartData.append(
|
|
MultipartFormData(
|
|
provider: .data(imageData),
|
|
name: "coverImage",
|
|
fileName: "\(UUID().uuidString)_\(Date().timeIntervalSince1970 * 1000).jpg",
|
|
mimeType: "image/*")
|
|
)
|
|
} else {
|
|
errorMessage = "커버이미지를 업로드 하지 못했습니다.\n다시 선택해 주세요"
|
|
isShowPopup = true
|
|
isLoading = false
|
|
return
|
|
}
|
|
|
|
if let selectedFileUrl = selectedFileUrl {
|
|
if selectedFileUrl.startAccessingSecurityScopedResource() {
|
|
defer {
|
|
selectedFileUrl.stopAccessingSecurityScopedResource()
|
|
}
|
|
|
|
if let data = try? Data(contentsOf: selectedFileUrl) {
|
|
multipartData.append(
|
|
MultipartFormData(
|
|
provider: .data(data),
|
|
name: "contentFile",
|
|
fileName: selectedFileUrl.lastPathComponent,
|
|
mimeType: "audio/*"
|
|
)
|
|
)
|
|
} else {
|
|
errorMessage = "콘텐츠 파일을 업로드 하지 못했습니다.\n다시 선택해 주세요"
|
|
isShowPopup = true
|
|
isLoading = false
|
|
return
|
|
}
|
|
} else {
|
|
errorMessage = "콘텐츠 파일을 업로드 하지 못했습니다.\n다시 선택해 주세요"
|
|
isShowPopup = true
|
|
isLoading = false
|
|
return
|
|
}
|
|
} else {
|
|
errorMessage = "콘텐츠 파일을 업로드 하지 못했습니다.\n다시 선택해 주세요"
|
|
isShowPopup = true
|
|
isLoading = false
|
|
return
|
|
}
|
|
|
|
multipartData.append(MultipartFormData(provider: .data(jsonData), name: "request"))
|
|
|
|
repository
|
|
.uploadAudioContent(parameters: multipartData)
|
|
.sink { result in
|
|
switch result {
|
|
case .finished:
|
|
DEBUG_LOG("finish")
|
|
case .failure(let error):
|
|
ERROR_LOG(error.localizedDescription)
|
|
}
|
|
} receiveValue: { [unowned self] response in
|
|
self.isLoading = false
|
|
let responseData = response.data
|
|
|
|
do {
|
|
let jsonDecoder = JSONDecoder()
|
|
let decoded = try jsonDecoder.decode(ApiResponseWithoutData.self, from: responseData)
|
|
|
|
if decoded.success {
|
|
self.isShowCompletePopup = true
|
|
} else {
|
|
if let message = decoded.message {
|
|
self.errorMessage = message
|
|
} else {
|
|
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
|
}
|
|
|
|
self.isShowPopup = true
|
|
}
|
|
} catch {
|
|
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
|
self.isShowPopup = true
|
|
}
|
|
}
|
|
.store(in: &subscription)
|
|
} else {
|
|
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
|
self.isShowPopup = true
|
|
self.isLoading = false
|
|
}
|
|
}
|
|
}
|
|
|
|
private func validateData() -> Bool {
|
|
if title.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
|
|
errorMessage = "제목을 입력해 주세요."
|
|
isShowPopup = true
|
|
return false
|
|
}
|
|
|
|
if detail.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty || detail.count < 5 {
|
|
errorMessage = "내용을 5자 이상 입력해 주세요."
|
|
isShowPopup = true
|
|
return false
|
|
}
|
|
|
|
if theme == nil {
|
|
errorMessage = "테마를 선택해 주세요."
|
|
isShowPopup = true
|
|
return false
|
|
}
|
|
|
|
if coverImage == nil {
|
|
errorMessage = "커버이미지를 선택해 주세요."
|
|
isShowPopup = true
|
|
return false
|
|
}
|
|
|
|
if selectedFileUrl == nil {
|
|
errorMessage = "오디오 콘텐츠를 선택해 주세요."
|
|
isShowPopup = true
|
|
return false
|
|
}
|
|
|
|
if !isFree && price < 5 {
|
|
errorMessage = "콘텐츠의 최소금액은 5캔 입니다."
|
|
isShowPopup = true
|
|
return false
|
|
}
|
|
|
|
if previewStartTime.count > 0 && previewEndTime.count > 0 {
|
|
let startTimeArray = previewStartTime.split(separator: ":")
|
|
if startTimeArray.count != 3 {
|
|
errorMessage = "미리 듣기 시간 형식은 00:30:00 과 같아야 합니다"
|
|
isShowPopup = true
|
|
return false
|
|
}
|
|
|
|
for time in startTimeArray {
|
|
if time.count != 2 {
|
|
errorMessage = "미리 듣기 시간 형식은 00:30:00 과 같아야 합니다"
|
|
isShowPopup = true
|
|
return false
|
|
}
|
|
}
|
|
|
|
let endTimeArray = previewStartTime.split(separator: ":")
|
|
if endTimeArray.count != 3 {
|
|
errorMessage = "미리 듣기 시간 형식은 00:30:00 과 같아야 합니다"
|
|
isShowPopup = true
|
|
return false
|
|
}
|
|
|
|
for time in endTimeArray {
|
|
if time.count != 2 {
|
|
errorMessage = "미리 듣기 시간 형식은 00:30:00 과 같아야 합니다"
|
|
isShowPopup = true
|
|
return false
|
|
}
|
|
}
|
|
|
|
let timeDifference = timeDifference(startTime: previewStartTime, endTime: previewEndTime)
|
|
if timeDifference < 15.0 {
|
|
errorMessage = "미리 듣기의 최소 시간은 15초 입니다"
|
|
isShowPopup = true
|
|
return false
|
|
}
|
|
} else {
|
|
if previewStartTime.count > 0 || previewEndTime.count > 0 {
|
|
errorMessage = "미리 듣기 시작 시간과 종료 시간 둘 다 입력을 하거나 둘 다 입력 하지 않아야 합니다."
|
|
isShowPopup = true
|
|
return false
|
|
}
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
private func timeDifference(startTime: String, endTime: String) -> Double {
|
|
let dateFormatter = DateFormatter()
|
|
dateFormatter.dateFormat = "HH:mm:ss"
|
|
|
|
if let date1 = dateFormatter.date(from: startTime), let date2 = dateFormatter.date(from: endTime) {
|
|
return date2.timeIntervalSince(date1)
|
|
}
|
|
|
|
return 0
|
|
}
|
|
}
|