Hi guys,
I have no idea how to implement a save functionality to the app. Is it better to use JSON or Core Data in my case?
Regarding the code I wrote, is it good or does it need improvement? Could you do a code review and give me some ideas for saving?
Thank you
import SwiftUI
struct ContentView: View {
@StateObject var dice = Dice(side: 4)
@State private var isShowingSettings = false
@State private var result: [Int] = []
var diceColors: [Color] = [.red, .blue, .green, .orange, .purple, .yellow, .indigo, .brown, .cyan, .gray, .mint, .pink]
@State private var color = 0
@State private var timer: Timer?
@State private var isActive = true
@State private var isDiceRolling = false
@Environment(\.scenePhase) var scenePhase
@State private var feedback = UINotificationFeedbackGenerator()
let savePath = FileManager.documentsDirectory.appendingPathComponent("SavedDiceInfo")
var body: some View {
NavigationView {
VStack {
Image(systemName: "dice")
.resizable()
.frame(width: 250, height: 250)
.padding(20)
.foregroundColor(diceColors[color])
Button {
withAnimation {
rollDice()
feedback.notificationOccurred(.success)
color = Int.random(in: 0...diceColors.count)
}
} label: {
Text("Roll")
.font(.largeTitle)
.padding()
.background(.blue)
.foregroundColor(.white)
.clipShape(Capsule())
.padding([.top, .bottom], 20)
}
.disabled(isDiceRolling)
Text("Result: \(result.last ?? 1)")
.font(.title)
}
.onChange(of: scenePhase, perform: { newPhase in
if newPhase == .active {
isActive = true
} else {
isActive = false
}
})
.toolbar {
Button {
isShowingSettings = true
} label: {
Image(systemName: "gearshape")
}
}
.sheet(isPresented: $isShowingSettings, content: {
SettingsView(dice: dice)
})
.navigationTitle("High Rollers")
}
}
func rollDice() {
isDiceRolling = true
feedback.prepare()
guard isActive else { return }
timer?.invalidate()
var rollCounter = 0
timer = Timer.scheduledTimer(withTimeInterval: 0.3, repeats: true, block: { _ in
result.append(dice.side == 1 ? 1 : Int.random(in: 1...dice.side))
rollCounter += 1
if rollCounter == 5 {
timer?.invalidate()
dice.results[Date.now] = result.last
isDiceRolling = false
print(result)
result = []
}
})
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
import SwiftUI
struct SettingsView: View {
@ObservedObject var dice: Dice
@State private var sideSelected = 4
@State private var number = 5
@Environment(\.dismiss) var dismiss
var body: some View {
NavigationView {
Form {
Section {
Picker("Select sides", selection: $sideSelected) {
ForEach(dice.sides, id: \.self) { side in
Text("\(side)-sided")
}
}
} header: {
Text("Dice Sides")
}
Section {
Picker("Add number", selection: $number) {
ForEach(0..<100) { num in
Text("\(num + 1)")
}
}
Button("Default", role: .destructive) {
dice.sides = [4, 6, 8, 10, 12, 20, 100]
}
} header: {
Text("Add Side Between 1 and 100")
}
Section {
List {
ForEach(dice.results.sorted(by: <), id: \.key) { key, value in
HStack {
Image(systemName: "dice.fill")
Spacer()
VStack(alignment: .leading) {
Text("\(value)")
.bold()
Text("\(key.formatted(date: .abbreviated, time: .omitted))")
.font(.caption)
}
}
}
.onDelete(perform: removePastRolls)
}
} header: {
Text("Past Rolls")
}
}
.navigationTitle("Settings")
.toolbar {
Button {
dice.side = sideSelected
if !dice.sides.contains(number + 1) {
dice.sides.append(number + 1)
dice.sides.sort()
}
dismiss()
} label: {
Text("Done")
}
}
}
}
func removePastRolls(at offset: IndexSet) {
if let ndx = offset.first {
let item = dice.results.sorted(by: >)[ndx]
dice.results.removeValue(forKey: item.key)
}
}
}
struct SettingsView_Previews: PreviewProvider {
static var previews: some View {
SettingsView(dice: Dice(side: 4))
}
}
import Foundation
class Dice: ObservableObject, Identifiable {
var id: UUID
@Published var side: Int
@Published var sides = [4, 6, 8, 10, 12, 20, 100].sorted()
@Published var results = [Date:Int]()
init(id: UUID = UUID(), side: Int, sides: [Int] = [4, 6, 8, 10, 12, 20, 100].sorted(), results: [Date : Int] = [Date:Int]()) {
self.id = id
self.side = side
self.sides = sides
self.results = results
}
}