sodalive-ios/SodaLive/Sources/FortuneWheel/FortuneWheelViewModel.swift

60 lines
2.3 KiB
Swift

//
// FortuneWheelViewModel.swift
// SodaLive
//
// Created by klaus on 2023/12/07.
//
import SwiftUI
class FortuneWheelViewModel: ObservableObject {
private var pendingRequestWorkItem: DispatchWorkItem?
@Published var degree = 0.0
private let model: FortuneWheelModel
init(model: FortuneWheelModel) {
self.model = model
}
private func getWheelStopDegree() -> Double {
var index = -1;
if let method = model.getWheelItemIndex { index = method() }
if index < 0 || index >= model.titles.count { index = Int.random(in: 0..<model.titles.count) }
index = model.titles.count - index - 1;
/*
itemRange - Each items degree range (For 4, each will have 360 / 4 = 90 degrees)
indexDegree - No. of 90 degrees to reach i item
freeRange - Flexible degree in the item, so the pointer doesn't always point start of the item
freeSpins - No. of spins before it goes to selected item index
finalDegree - Final exact degree to spin and stop in the index
*/
let itemRange = 360 / model.titles.count;
let indexDegree = itemRange * index;
let freeRange = Int.random(in: 0...itemRange);
let freeSpins = (2...20).map({ return $0 * 360 }).randomElement()!
let finalDegree = freeSpins + indexDegree + freeRange;
return Double(finalDegree);
}
func spinWheel() {
withAnimation(model.animation) {
self.degree = Double(360 * Int(self.degree / 360)) + getWheelStopDegree();
}
// Cancel the currently pending item
pendingRequestWorkItem?.cancel()
// Wrap our request in a work item
let requestWorkItem = DispatchWorkItem { [weak self] in
guard let self = self else { return }
let count = self.model.titles.count
let distance = self.degree.truncatingRemainder(dividingBy: 360)
let pointer = floor(distance / (360 / Double(count)))
if let onSpinEnd = self.model.onSpinEnd { onSpinEnd(count - Int(pointer) - 1) }
}
// Save the new work item and execute it after duration
pendingRequestWorkItem = requestWorkItem
DispatchQueue.main.asyncAfter(deadline: .now() + model.animDuration + 1, execute: requestWorkItem)
}
}