349 lines
12 KiB
Swift
349 lines
12 KiB
Swift
//
|
|
// PortraitView.swift
|
|
// Bunch O' Dice
|
|
//
|
|
// Created by Rory Hinnen on 22/6/18.
|
|
//
|
|
|
|
import SwiftUI
|
|
|
|
struct MainView: View {
|
|
|
|
enum MenuView: Int {
|
|
case history, add, settings
|
|
|
|
func icon() -> Image {
|
|
switch self {
|
|
case .history:
|
|
return(Image(systemName: "folder"))
|
|
case .settings:
|
|
return(Image(systemName: "square.and.pencil"))
|
|
case .add:
|
|
return(Image(systemName: "folder.badge.plus"))
|
|
}
|
|
}
|
|
}
|
|
|
|
@ViewBuilder private func myCircle() -> some View {
|
|
Circle()
|
|
.fill(Color.gray)
|
|
.blur(radius: 2.0)
|
|
.frame(width: controlSize*2.5, height: controlSize*2.5, alignment: .center)
|
|
}
|
|
|
|
@ViewBuilder private func stateView() -> some View {
|
|
switch current.state {
|
|
case .wound:
|
|
woundCalculator(controlSize: controlSize)
|
|
case .armour:
|
|
armourCalculator(controlSize: controlSize)
|
|
default:
|
|
hitCalculator(controlSize: controlSize)
|
|
}
|
|
}
|
|
|
|
@ViewBuilder private func sheetContent() -> some View {
|
|
switch sheet.state {
|
|
case .settings:
|
|
SettingsView(isShowing: $sheet.isShowing)
|
|
case .history:
|
|
HistoryView(isShowing: $sheet.isShowing)
|
|
default:
|
|
EmptyView()
|
|
}
|
|
}
|
|
|
|
@ViewBuilder func buttons(color: CGColor, label: String, value: Int) -> some View {
|
|
let frameSize = 120.0
|
|
let fontSize = 35.0
|
|
let blurSize = 5.0
|
|
|
|
ZStack {
|
|
Circle()
|
|
.fill(Color(color))
|
|
.frame(width: frameSize, height: frameSize)
|
|
.blur(radius: blurSize)
|
|
VStack{
|
|
Text(String(value))
|
|
.fontWeight(.black)
|
|
Text(label)
|
|
.font(.system(size: 20))
|
|
}
|
|
}
|
|
.foregroundColor(.primary)
|
|
.font(.system(size: fontSize))
|
|
}
|
|
|
|
//MARK: State Views
|
|
@ViewBuilder func armourCalculator(controlSize: Double) -> some View {
|
|
HStack(alignment: .top) {
|
|
Spacer()
|
|
VStack {
|
|
Text("Armour")
|
|
Group {
|
|
Text("▲")
|
|
.gesture(TapGesture() .onEnded {
|
|
current.addPenetration()
|
|
})
|
|
Text(
|
|
(current.armourPenetration > 0 ?
|
|
"+" : "") +
|
|
String(current.armourPenetration))
|
|
Text("▼")
|
|
.gesture(TapGesture() .onEnded {
|
|
current.losePenetration()
|
|
})
|
|
}
|
|
.font(.system(size: controlSize))
|
|
Text("Penetration")
|
|
}
|
|
Spacer()
|
|
VStack{
|
|
Text("Invulnerable")
|
|
Toggle("", isOn: $current.invulnerable).labelsHidden()
|
|
.padding()
|
|
}
|
|
Spacer()
|
|
VStack{
|
|
Text("Reroll")
|
|
Button("🎲", action: {
|
|
current.dice.roll(howMany: current.total)
|
|
})
|
|
.padding()
|
|
.font(.system(size: controlSize))
|
|
}
|
|
Spacer()
|
|
}
|
|
.padding()
|
|
}
|
|
|
|
@ViewBuilder func woundCalculator(controlSize: Double) -> some View {
|
|
HStack(alignment: .top) {
|
|
Spacer()
|
|
VStack {
|
|
Text("Attack")
|
|
Group {
|
|
Text("▲")
|
|
.gesture(TapGesture() .onEnded {
|
|
current.addStrength()
|
|
})
|
|
Text(String(current.strength))
|
|
Text("▼")
|
|
.gesture(TapGesture() .onEnded {
|
|
current.loseStrength()
|
|
})
|
|
}.font(.system(size: controlSize))
|
|
Text("Strength")
|
|
}
|
|
|
|
Spacer()
|
|
VStack {
|
|
Text("Toughness")
|
|
Group {
|
|
Text("▲")
|
|
.gesture(TapGesture() .onEnded {
|
|
current.addToughness()
|
|
})
|
|
Text(String(current.toughness))
|
|
Text("▼")
|
|
.gesture(TapGesture() .onEnded {
|
|
current.loseToughness()
|
|
})
|
|
}.font(.system(size: controlSize))
|
|
Text(" ")
|
|
}
|
|
Spacer()
|
|
VStack {
|
|
Text("Wound")
|
|
.multilineTextAlignment(.center)
|
|
Group {
|
|
Text("▲")
|
|
.gesture(TapGesture() .onEnded {
|
|
current.woundModifier = current.woundModifier.add()
|
|
})
|
|
Text(
|
|
(current.woundModifier.rawValue > 0 ?
|
|
"+" : "") +
|
|
String(current.woundModifier.rawValue))
|
|
Text("▼")
|
|
.gesture(TapGesture() .onEnded {
|
|
current.woundModifier = current.woundModifier.remove()
|
|
})
|
|
}.font(.system(size: controlSize))
|
|
Text("Modifier")
|
|
}
|
|
Spacer()
|
|
VStack{
|
|
Text("Reroll")
|
|
Button("🎲", action: {
|
|
current.dice.roll(howMany: current.total)
|
|
})
|
|
.padding()
|
|
.font(.system(size: controlSize))
|
|
}
|
|
Spacer()
|
|
}.padding()
|
|
}
|
|
|
|
@ViewBuilder func hitCalculator(controlSize: Double) -> some View {
|
|
HStack(alignment: .top) {
|
|
Group {
|
|
VStack {
|
|
Text("Hit")
|
|
.multilineTextAlignment(.center)
|
|
Group {
|
|
Text("▲")
|
|
.gesture(TapGesture() .onEnded {
|
|
current.modifier = current.modifier.add()
|
|
})
|
|
Text( (current.modifier.rawValue > 0 ?
|
|
"+" : "") +
|
|
String(current.modifier.rawValue))
|
|
Text("▼")
|
|
.gesture(TapGesture() .onEnded {
|
|
current.modifier = current.modifier.remove()
|
|
})
|
|
}
|
|
.font(.system(size: controlSize))
|
|
Text("Modifier")
|
|
}
|
|
VStack {
|
|
Text("Blow Up")
|
|
VStack {
|
|
Button(action: {current.dice.blowup(dice: .six)})
|
|
{Image(systemName: "die.face.6")
|
|
.foregroundColor(.primary)
|
|
}
|
|
Button(action: {current.dice.blowup(dice: .five)})
|
|
{Image(systemName: "die.face.5")
|
|
.foregroundColor(.primary)
|
|
}
|
|
}
|
|
.padding()
|
|
.font(.system(size: controlSize))
|
|
|
|
}
|
|
VStack{
|
|
Text("Reroll")
|
|
Button("🎲", action: {
|
|
current.dice.roll(howMany: current.total)
|
|
})
|
|
.padding()
|
|
.font(.system(size: controlSize))
|
|
}
|
|
}
|
|
}.padding()
|
|
}
|
|
|
|
//MARK: die views
|
|
@ViewBuilder func die(whichDie: Dice.DiceType) -> some View {
|
|
let size = 30.0
|
|
let displayColorHit = (whichDie.rawValue >= current.cutoff.rawValue) ? Color.red : Color.primary
|
|
let displayColorArmor = (whichDie.rawValue <= current.cutoff.rawValue) ? Color.red : Color.primary
|
|
let displayColorArmorText = (whichDie.rawValue < current.cutoff.rawValue) ? Color.red : Color.primary
|
|
|
|
HStack{
|
|
Text(String(current.dice.value(which: whichDie)))
|
|
.foregroundColor(current.state == .armour ?
|
|
displayColorArmorText : displayColorHit)
|
|
Image(systemName: "die.face." + String(whichDie.rawValue) + ".fill")
|
|
.foregroundColor(current.state == .armour ?
|
|
displayColorArmor : displayColorHit)
|
|
|
|
}
|
|
.font(.system(size: size))
|
|
.padding(2)
|
|
.gesture(TapGesture().onEnded {
|
|
if current.state == .hit {
|
|
if whichDie.rawValue != 1 {
|
|
current.hitCutoff = whichDie }
|
|
} else if current.state == .armour {
|
|
current.armourSave = Int(whichDie.rawValue)
|
|
}
|
|
})
|
|
}
|
|
|
|
@ViewBuilder func diePool() -> some View {
|
|
VStack(alignment: .leading) {
|
|
ForEach(Dice.DiceType.allCases.reversed(), id: \.rawValue) { i in
|
|
die(whichDie: i)
|
|
}
|
|
}
|
|
}
|
|
|
|
//MARK: Var declarations
|
|
@EnvironmentObject var current: Roll
|
|
@ObservedObject var sheet = SettingsSheet()
|
|
@State var showFillView = false
|
|
|
|
let padSize = 60.0
|
|
let controlSize = 30.0
|
|
let red = CGColor(red: 1.0, green: 0.3, blue: 0.3, alpha: 1.0)
|
|
let blue = CGColor(red: 0.3, green: 0.3, blue: 1.0, alpha: 1.0)
|
|
|
|
var body: some View {
|
|
VStack{
|
|
HStack{
|
|
Button(action: {current.state = .hit}) {
|
|
ZStack{
|
|
if current.state == .hit {myCircle()}
|
|
Text(RollState.hit.print())}}
|
|
Button(action: {current.state = .wound}) {
|
|
ZStack{
|
|
if current.state == .wound {myCircle()}
|
|
Text(RollState.wound.print())}}
|
|
Button(action: {current.state = .armour}) {
|
|
ZStack{
|
|
if current.state == .armour {myCircle()}
|
|
Text(RollState.armour.print())}}
|
|
}.font(.system(size: 60))
|
|
VStack{
|
|
HStack {
|
|
VStack {
|
|
Button(action: {showFillView.toggle()}) {
|
|
buttons(color: blue, label: "Pool", value: current.total)
|
|
}
|
|
.sheet(isPresented: $showFillView,
|
|
onDismiss: {current.dice.roll(howMany: current.total)}) {
|
|
VStack {
|
|
AddToPool()
|
|
Button("Accept", action: {showFillView.toggle()})
|
|
.padding(20)
|
|
}
|
|
}
|
|
Spacer()
|
|
Button(action: current.incrementState) {
|
|
buttons(color: red, label: current.state.text(), value: current.result)
|
|
}
|
|
|
|
}.padding(.leading, padSize)
|
|
Spacer()
|
|
diePool().padding(.trailing, padSize)
|
|
}.frame(maxHeight: 285)
|
|
stateView()
|
|
}.padding()
|
|
}
|
|
.toolbar {
|
|
ToolbarItemGroup(placement: .bottomBar) {
|
|
HStack {
|
|
Button(action: {self.sheet.state = .history}) {
|
|
MenuView.history.icon()}
|
|
Button(action: {current.history.insert(Event(total: current.result, pool: current.dice, state: current.state), at: 0)}) {
|
|
MenuView.add.icon()}
|
|
Button(action: {self.sheet.state = .settings}) {
|
|
MenuView.settings.icon()}
|
|
}
|
|
.font(.system(size: controlSize))
|
|
.foregroundColor(.primary)
|
|
}
|
|
}
|
|
.sheet(isPresented: $sheet.isShowing, content: sheetContent)}
|
|
}
|
|
|
|
struct MainView_Previews: PreviewProvider {
|
|
static var previews: some View {
|
|
MainView()
|
|
.environmentObject(Roll())
|
|
}
|
|
}
|