// // 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") Picker("", selection: $current.saveRerollMode) { ForEach(RerollMode.allCases, id: \.self) { mode in Text(mode.label).tag(mode) } } .pickerStyle(.segmented) .frame(width: 180) Button("🎲") { current.applyReroll() } .disabled(current.saveRerollMode == .none || current.saveHasRerolled) .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") Picker("", selection: $current.woundRerollMode) { ForEach(RerollMode.allCases, id: \.self) { mode in Text(mode.label).tag(mode) } } .pickerStyle(.segmented) .frame(width: 180) Button("🎲") { current.applyReroll() } .disabled(current.woundRerollMode == .none || current.woundHasRerolled) .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") Picker("", selection: $current.hitRerollMode) { ForEach(RerollMode.allCases, id: \.self) { mode in Text(mode.label).tag(mode) } } .pickerStyle(.segmented) .frame(width: 180) Button("🎲") { current.applyReroll() } .disabled(current.hitRerollMode == .none || current.hitHasRerolled) .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.resetPool() }) { 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()) } }