You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
221 lines
6.1 KiB
221 lines
6.1 KiB
//
|
|
// StoreView.swift
|
|
// LeCountdown
|
|
//
|
|
// Created by Laurent Morvillier on 17/02/2023.
|
|
//
|
|
|
|
import SwiftUI
|
|
import StoreKit
|
|
|
|
fileprivate enum Feature: Int, Identifiable, CaseIterable {
|
|
case unlimitedTimers
|
|
case allSounds
|
|
case longSounds
|
|
case allStats
|
|
|
|
var id: Int { self.rawValue }
|
|
|
|
var localizedString: String {
|
|
switch self {
|
|
case .unlimitedTimers: return NSLocalizedString("Unlimited timers and stopwatches", comment: "")
|
|
case .allSounds: return NSLocalizedString("Access all the sound library", comment: "")
|
|
case .longSounds: return NSLocalizedString("Access long version of sounds", comment: "")
|
|
case .allStats: return NSLocalizedString("See all your activities in detail", comment: "")
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
struct StoreView: View, StoreDelegate {
|
|
|
|
@StateObject private var store: Store = Store()
|
|
|
|
@State private var errorMessage: String? = nil
|
|
|
|
@Binding var isPresented: Bool
|
|
|
|
var body: some View {
|
|
|
|
Group {
|
|
if !self.store.products.isEmpty {
|
|
PlanView(isPresented: self.$isPresented)
|
|
.environmentObject(self.store)
|
|
} else {
|
|
ProgressView()
|
|
.progressViewStyle(.circular)
|
|
}
|
|
}.onAppear {
|
|
self._configure()
|
|
}
|
|
|
|
}
|
|
|
|
fileprivate func _configure() {
|
|
self.store.delegate = self
|
|
}
|
|
|
|
// MARK: - StoreDelegate
|
|
|
|
func productsReceived() {
|
|
|
|
}
|
|
|
|
func errorDidOccur(error: Error) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
struct PlanView: View {
|
|
|
|
@EnvironmentObject var store: Store
|
|
|
|
@State var _loadingProduct: String? = nil
|
|
@State var _purchased: Bool = false
|
|
|
|
@Binding var isPresented: Bool
|
|
|
|
var body: some View {
|
|
|
|
VStack {
|
|
|
|
Text("Permanent enchantment")
|
|
.font(.title)
|
|
.fontWeight(.bold)
|
|
.padding()
|
|
|
|
Group {
|
|
ForEach(Feature.allCases) { feature in
|
|
HStack {
|
|
Text(feature.localizedString)
|
|
Spacer()
|
|
Image(systemName: "checkmark.circle.fill")
|
|
.foregroundColor(.accentColor)
|
|
}.fontWeight(.medium)
|
|
}
|
|
}
|
|
.padding(.horizontal, 24.0)
|
|
.padding(.vertical, 2.0)
|
|
|
|
Spacer()
|
|
|
|
PlayerWrapperView()
|
|
|
|
Text("Purchase").font(.title)
|
|
|
|
ForEach(self.store.products) { product in
|
|
|
|
Button {
|
|
self._purchase(product: product)
|
|
} label: {
|
|
HStack {
|
|
Spacer()
|
|
|
|
if product.id == self._loadingProduct {
|
|
if self._purchased {
|
|
Image(systemName: "checkmark.circle.fill")
|
|
} else {
|
|
ProgressView()
|
|
.progressViewStyle(.circular).tint(.white)
|
|
}
|
|
} else {
|
|
VStack {
|
|
if let plan = StorePlan(rawValue: product.id) {
|
|
Text("\(product.displayPrice) / \(plan.formattedPeriod)").font(.title3)
|
|
.foregroundColor(.white)
|
|
} else {
|
|
Text("Plan not found")
|
|
}
|
|
}
|
|
}
|
|
Spacer()
|
|
}.frame(height: 44.0)
|
|
|
|
}
|
|
.buttonStyle(.borderedProminent)
|
|
.fontWeight(.medium)
|
|
}
|
|
|
|
}.padding()
|
|
.foregroundColor(.black)
|
|
.background(Color(red: 1.0, green: 0.8, blue: 0.9))
|
|
}
|
|
|
|
fileprivate func _purchase(product: Product) {
|
|
Task {
|
|
self._loadingProduct = product.id
|
|
let result = try await store.purchase(product)
|
|
switch result {
|
|
case .none:
|
|
self._loadingProduct = nil
|
|
case .some:
|
|
self._purchased = true
|
|
self.isPresented = false
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
struct PlayerWrapperView: View {
|
|
|
|
@StateObject var player: StatePlayer = StatePlayer()
|
|
|
|
var body: some View {
|
|
|
|
let state = self.player.state
|
|
Group {
|
|
|
|
switch state {
|
|
case .none, .paused:
|
|
Button {
|
|
self._pause()
|
|
} label: {
|
|
HStack {
|
|
Image(systemName: state.systemImage)
|
|
Spacer()
|
|
ProgressView(value: self.player.completion)
|
|
}.font(.title)
|
|
}.buttonStyle(.borderedProminent)
|
|
.fontWeight(.medium)
|
|
|
|
case .playing:
|
|
Button {
|
|
self._pause()
|
|
} label: {
|
|
HStack {
|
|
Image(systemName: state.systemImage)
|
|
Spacer()
|
|
ProgressView(value: self.player.completion)
|
|
|
|
// Slider(value: self.$player.completion)
|
|
}.font(.title)
|
|
}.buttonStyle(.borderedProminent)
|
|
.fontWeight(.medium)
|
|
case .noResource:
|
|
EmptyView()
|
|
}
|
|
|
|
}
|
|
.onAppear {
|
|
self.player.load(resource: "QP01 0118 Riparian Zone thrush", ext: "wav")
|
|
}
|
|
|
|
}
|
|
|
|
fileprivate func _play() {
|
|
self.player.play()
|
|
}
|
|
|
|
fileprivate func _pause() {
|
|
self.player.pause()
|
|
}
|
|
|
|
}
|
|
|
|
struct StoreView_Previews: PreviewProvider {
|
|
static var previews: some View {
|
|
PlanView(isPresented: .constant(false)).environmentObject(Store())
|
|
}
|
|
}
|
|
|