sodalive-ios/SodaLive/Sources/Live/Room/Routlette/Config/RouletteSettingsViewModel.s...

356 lines
12 KiB
Swift

//
// RouletteSettingsViewModel.swift
// SodaLive
//
// Created by klaus on 2023/12/05.
//
import Foundation
import Combine
enum SelectedRoulette: Int {
case ROULETTE_1 = 0
case ROULETTE_2 = 1
case ROULETTE_3 = 2
}
final class RouletteSettingsViewModel: ObservableObject {
private let repository = RouletteRepository()
private var subscription = Set<AnyCancellable>()
@Published var isLoading = false
@Published var errorMessage = ""
@Published var isShowErrorPopup = false
@Published var canText = "" {
didSet {
can = Int(canText) ?? 0
}
}
@Published var isActive = false
@Published var options = [RouletteOption]()
@Published var isShowPreview = false {
didSet {
if !isShowPreview {
previewData = nil
}
}
}
@Published var previewData: RoulettePreview? = nil
@Published var selectedRoulette: SelectedRoulette? = nil
var can = 0
private var rouletteId = 0
@Published var rouletteList = [GetNewRouletteResponse]()
func plusWeight(index: Int) {
options[index].weight += 1
recalculatePercentages()
}
func subtractWeight(index: Int) {
if options[index].weight > 1 {
options[index].weight -= 1
recalculatePercentages()
}
}
func addOption() {
if (options.count >= 10) {
return
}
options.append(RouletteOption(title: "", weight: 1))
recalculatePercentages()
}
func deleteOption(index: Int) {
options.remove(at: index)
recalculatePercentages()
}
private func recalculatePercentages() {
let options = options
var totalWeight = 0
for option in options {
totalWeight += option.weight
}
guard totalWeight > 0 else { return }
for i in 0..<options.count {
let percent = floor(Double(options[i].weight) / Double(totalWeight) * 10000) / 100
options[i].percentage = String(format: "%.2f", percent)
}
removeAllAndAddOptions(options: options)
}
private func removeAllAndAddOptions(options: [RouletteOption]) {
self.options.removeAll()
self.options.append(contentsOf: options)
}
func getAllRoulette(creatorId: Int) {
self.isLoading = true
repository.getAllRoulette(creatorId: creatorId)
.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(ApiResponse<[GetNewRouletteResponse]>.self, from: responseData)
if let data = decoded.data, decoded.success {
rouletteList.removeAll()
rouletteList.append(contentsOf: data)
selectRoulette(selectedRoulette: .ROULETTE_1)
} else {
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
self.isShowErrorPopup = true
}
} catch {
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
self.isShowErrorPopup = true
}
}
.store(in: &subscription)
}
func onClickPreview() {
isLoading = true
var items = [RoulettePreviewItem]()
for option in options {
if option.title.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
isLoading = false
errorMessage = "옵션은 빈칸일 수 없습니다."
isShowErrorPopup = true
return
}
items.append(RoulettePreviewItem(title: option.title, percent: "\(option.percentage)%"))
}
previewData = RoulettePreview(can: self.can, items: items)
isLoading = false
isShowPreview = true
}
func createOrUpdateRoulette(onSuccess: @escaping (Bool, String) -> Void) {
if !isLoading {
isLoading = true
if rouletteId > 0 {
updateRoulette(onSuccess: onSuccess)
} else {
createRoulette(onSuccess: onSuccess)
}
}
}
private func createRoulette(onSuccess: @escaping (Bool, String) -> Void) {
var items = [RouletteItem]()
for option in options {
if option.title.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
isLoading = false
errorMessage = "옵션은 빈칸일 수 없습니다."
isShowErrorPopup = true
return
}
items.append(RouletteItem(title: option.title, weight: option.weight))
}
let selectedRouletteTitle: String
let successMessage: String
switch (self.selectedRoulette) {
case .ROULETTE_2:
selectedRouletteTitle = "룰렛 2"
case .ROULETTE_3:
selectedRouletteTitle = "룰렛 3"
default:
selectedRouletteTitle = "룰렛 1"
}
if isActive {
successMessage = "\(selectedRouletteTitle)로 설정하였습니다."
} else {
successMessage = "\(selectedRouletteTitle)을 설정했습니다."
}
let request = CreateRouletteRequest(can: can, isActive: isActive, items: items)
repository.createRoulette(request: request)
.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 {
onSuccess(isActive, successMessage)
} else {
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
self.isShowErrorPopup = true
}
} catch {
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
self.isShowErrorPopup = true
}
}
.store(in: &subscription)
}
private func updateRoulette(onSuccess: @escaping (Bool, String) -> Void) {
var items = [RouletteItem]()
for option in options {
if option.title.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
isLoading = false
errorMessage = "옵션은 빈칸일 수 없습니다."
isShowErrorPopup = true
return
}
items.append(RouletteItem(title: option.title, weight: option.weight))
}
let selectedRoulette = rouletteList[selectedRoulette!.rawValue]
if selectedRoulette.isActive == isActive && selectedRoulette.can == can && selectedRoulette.items == items {
self.errorMessage = "변동사항이 없습니다."
self.isShowErrorPopup = true
self.isLoading = false
return
}
let selectedRouletteTitle: String
let successMessage: String
switch (self.selectedRoulette) {
case .ROULETTE_2:
selectedRouletteTitle = "룰렛 2"
case .ROULETTE_3:
selectedRouletteTitle = "룰렛 3"
default:
selectedRouletteTitle = "룰렛 1"
}
var isAllActive = false
rouletteList
.filter {
$0.id != selectedRoulette.id
}
.forEach {
if $0.isActive {
isAllActive = true
}
}
if isActive {
successMessage = "\(selectedRouletteTitle)로 설정하였습니다."
} else if !isAllActive {
successMessage = "\(selectedRouletteTitle)이 비활성화 되었습니다."
} else {
successMessage = "\(selectedRouletteTitle)을 설정했습니다."
}
let request = UpdateRouletteRequest(id: rouletteId, can: can, isActive: isActive, items: items)
repository.updateRoulette(request: request)
.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 {
onSuccess(isActive, successMessage)
} else {
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
self.isShowErrorPopup = true
}
} catch {
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
self.isShowErrorPopup = true
}
}
.store(in: &subscription)
}
func selectRoulette(selectedRoulette: SelectedRoulette) {
if rouletteList.isEmpty && (selectedRoulette == .ROULETTE_2 || selectedRoulette == .ROULETTE_3) {
errorMessage = "룰렛 1을 먼저 설정하세요"
isShowErrorPopup = true
return
}
if rouletteList.count == 1 && selectedRoulette == .ROULETTE_3 {
errorMessage = "룰렛 1과 룰렛 2를 먼저 설정하세요"
isShowErrorPopup = true
return
}
if self.selectedRoulette != selectedRoulette {
self.selectedRoulette = selectedRoulette
if rouletteList.count > selectedRoulette.rawValue {
let roulette = rouletteList[selectedRoulette.rawValue]
if roulette.can > 0 {
self.canText = String(roulette.can)
} else {
self.canText = ""
}
self.rouletteId = roulette.id
self.isActive = roulette.isActive
let options = roulette.items.map {
RouletteOption(title: $0.title, weight: $0.weight)
}
removeAllAndAddOptions(options: options)
recalculatePercentages()
} else {
self.canText = ""
self.isActive = false
self.rouletteId = 0
options.removeAll()
self.addOption()
self.addOption()
}
}
}
}