Files
MonsterCards/iOS/MonsterCards/Views/EditMonster.swift

425 lines
19 KiB
Swift

//
// EditMonster.swift
// MonsterCards
//
// Created by Tom Hicks on 1/16/21.
//
import CoreData
import SwiftUI
struct EditMonster: View {
// TODO: add challengeRating/challengeRatingEnum and customChallengeRating maybe in basicInfo
@Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
@Environment(\.managedObjectContext) private var viewContext
var monster: Monster
@State private var monsterName: String = ""
@State private var monsterSize: String = ""
@State private var monsterType: String = ""
@State private var monsterSubtype: String = ""
@State private var monsterAlignment: String = ""
@State private var monsterHitDice: Int64 = 0
@State private var monsterHasCustomHP: Bool = false
@State private var monsterCustomHP: String = ""
@State private var monsterArmorType: ArmorType = ArmorType.none
@State private var monsterHasShield: Bool = false
@State private var monsterNaturalArmorBonus: Int64 = 0
@State private var monsterCustomArmor: String = ""
@State private var monsterBaseSpeed: Int64 = 0
@State private var monsterBurrowSpeed: Int64 = 0
@State private var monsterClimbSpeed: Int64 = 0
@State private var monsterFlySpeed: Int64 = 0
@State private var monsterCanHover: Bool = false
@State private var monsterSwimSpeed: Int64 = 0
@State private var monsterHasCustomSpeed: Bool = false
@State private var monsterCustomSpeed: String = ""
@State private var monsterStrengthScore: Int64 = 10
@State private var monsterDexterityScore: Int64 = 10
@State private var monsterConstitutionScore: Int64 = 10
@State private var monsterIntelligenceScore: Int64 = 10
@State private var monsterWisdomScore: Int64 = 10
@State private var monsterCharismaScore: Int64 = 10
@State private var monsterStrengthSavingThrowProficiency: ProficiencyType = .none
@State private var monsterStrengthSavingThrowAdvantage: AdvantageType = .none
@State private var monsterDexteritySavingThrowProficiency: ProficiencyType = .none
@State private var monsterDexteritySavingThrowAdvantage: AdvantageType = .none
@State private var monsterConstitutionSavingThrowProficiency: ProficiencyType = .none
@State private var monsterConstitutionSavingThrowAdvantage: AdvantageType = .none
@State private var monsterIntelligenceSavingThrowProficiency: ProficiencyType = .none
@State private var monsterIntelligenceSavingThrowAdvantage: AdvantageType = .none
@State private var monsterWisdomSavingThrowProficiency: ProficiencyType = .none
@State private var monsterWisdomSavingThrowAdvantage: AdvantageType = .none
@State private var monsterCharismaSavingThrowProficiency: ProficiencyType = .none
@State private var monsterCharismaSavingThrowAdvantage: AdvantageType = .none
var body: some View {
List {
Section(header: Text("Basic Info")) {
// Editable Text field bound to monster.name
MCTextField(
label: "Name",
value: $monsterName)
// Editable Text field bound to monster.size
MCTextField(
label: "Size",
value: $monsterSize)
// Editable Text field bound to monster.type
MCTextField(
label: "Type",
value: $monsterType)
// Editable Text field bound to monster.subType
MCTextField(
label: "Subtype",
value: $monsterSubtype)
// Editable Text field bound to monster.alignment
MCTextField(
label: "Alignment",
value: $monsterAlignment)
// Number with -/+ buttons bound to monster.hitDice
MCStepperField(
label: "Hit Dice",
value: $monsterHitDice)
// Toggle bound to monster.hasCustomHP?
Toggle(
"Has Custom HP",
isOn:$monsterHasCustomHP)
// Editable Text field bound to monster.customHpText?
MCTextField(
label: "Custom HP",
value: $monsterCustomHP)
}
.textCase(nil)
Section(header: Text("Armor")) {
// Armor Type select bound to monster.armorTypeEnum
MCArmorTypePicker(
label: "Armor Type",
value: $monsterArmorType)
// Toggle bound to monster.hasShield?
Toggle(
"Has Shield",
isOn: $monsterHasShield)
// Number with -/+ buttons bound to monster.naturalArmorBonus
MCStepperField(
label: "Natural Armor Bonus",
value: $monsterNaturalArmorBonus)
// Editable Text field bound to monster.customArmorText?
MCTextField(
label: "Custom Armor",
value: $monsterCustomArmor)
}
.textCase(nil)
Section(header: Text("Speed")) {
// Number bound to monster.baseSpeed
MCStepperField(
label: "Base",
step: 5,
suffix: " ft.",
value: $monsterBaseSpeed)
// Number bound to monster.burrowSpeed
MCStepperField(
label: "Burrow",
step: 5,
suffix: " ft.",
value: $monsterBurrowSpeed)
// Number bound to monster.climbSpeed
MCStepperField(
label: "Climb",
step: 5,
suffix: " ft.",
value: $monsterClimbSpeed)
// Number bound to monster.flySpeed
MCStepperField(
label: "Fly",
step: 5,
suffix: " ft.",
value: $monsterFlySpeed)
// Toggle bound to monster.canHover
Toggle(
"Can Hover",
isOn: $monsterCanHover)
// Number bound to monster.swimSpeed
MCStepperField(
label: "Swim",
step: 5,
suffix: " ft.",
value: $monsterSwimSpeed)
// Toggle bound to monster.hasCustomSpeed
Toggle(
"Has Custom Speed",
isOn: $monsterHasCustomSpeed)
// Editable Text field bound to monster.customSpeedText
MCTextField(
label: "Custom Speed",
value: $monsterCustomSpeed)
}
.textCase(nil)
Section(header: Text("Ability Scores")) {
MCStepperField(
label: "STR",
value: $monsterStrengthScore)
MCStepperField(
label: "DEX",
value: $monsterDexterityScore)
MCStepperField(
label: "CON",
value: $monsterConstitutionScore)
MCStepperField(
label: "INT",
value: $monsterIntelligenceScore)
MCStepperField(
label: "WIS",
value: $monsterWisdomScore)
MCStepperField(
label: "CHA",
value: $monsterCharismaScore)
}
.textCase(nil)
Section(header: Text("Saving Throws")) {
VStack {
MCAdvantagePicker(
label: "Strength Advantage",
value: $monsterStrengthSavingThrowAdvantage)
MCProficiencyPicker(
label: "Strength Proficiency",
value: $monsterStrengthSavingThrowProficiency)
}
VStack {
MCAdvantagePicker(
label: "Dexterity Advantage",
value: $monsterDexteritySavingThrowAdvantage)
MCProficiencyPicker(
label: "Dexterity Proficiency",
value: $monsterDexteritySavingThrowProficiency)
}
VStack {
MCAdvantagePicker(
label: "Constitution Advantage",
value: $monsterConstitutionSavingThrowAdvantage)
MCProficiencyPicker(
label: "Constitution Proficiency",
value: $monsterConstitutionSavingThrowProficiency)
}
VStack {
MCAdvantagePicker(
label: "Intelligence Advantage",
value: $monsterIntelligenceSavingThrowAdvantage)
MCProficiencyPicker(
label: "Intelligence Proficiency",
value: $monsterIntelligenceSavingThrowProficiency)
}
VStack {
MCAdvantagePicker(
label: "Wisdom Advantage",
value: $monsterWisdomSavingThrowAdvantage)
MCProficiencyPicker(
label: "Wisdom Proficiency",
value: $monsterWisdomSavingThrowProficiency)
}
VStack {
MCAdvantagePicker(
label: "Charisma Advantage",
value: $monsterCharismaSavingThrowAdvantage)
MCProficiencyPicker(
label: "Charisma Proficiency",
value: $monsterCharismaSavingThrowProficiency)
}
}
.textCase(nil)
}
.onAppear(perform: copyMonsterToLocal)
.toolbar(content: {
ToolbarItem(placement: .primaryAction) {
Button("Save", action: saveMonster)
}
ToolbarItem(placement: ToolbarItemPlacement.cancellationAction) {
Button("Cancel", action: cancel)
}
})
.navigationTitle(monster.name ?? "")
.navigationBarTitleDisplayMode(.inline)
.navigationBarBackButtonHidden(true)
}
private func dismissView() {
self.presentationMode.wrappedValue.dismiss()
}
private func saveMonster() {
copyLocalToMonster()
do {
try viewContext.save()
} catch {
// Replace this implementation with code to handle the error appropriately.
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
let nsError = error as NSError
fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
}
// TODO: save coredata context
dismissView()
}
private func cancel() {
dismissView()
}
private func copyMonsterToLocal() {
monsterName = monster.name ?? ""
monsterSize = monster.size ?? ""
monsterType = monster.type ?? ""
monsterSubtype = monster.subtype ?? ""
monsterAlignment = monster.alignment ?? ""
monsterHitDice = monster.hitDice
monsterHasCustomHP = monster.hasCustomHP
monsterCustomHP = monster.customHP ?? ""
monsterArmorType = monster.armorTypeEnum
monsterHasShield = monster.hasShield
monsterNaturalArmorBonus = monster.naturalArmorBonus
monsterCustomArmor = monster.customArmor ?? ""
monsterBaseSpeed = monster.baseSpeed
monsterBurrowSpeed = monster.burrowSpeed
monsterClimbSpeed = monster.climbSpeed
monsterFlySpeed = monster.flySpeed
monsterCanHover = monster.canHover
monsterSwimSpeed = monster.swimSpeed
monsterHasCustomSpeed = monster.hasCustomSpeed
monsterCustomSpeed = monster.customSpeed ?? ""
monsterStrengthScore = monster.strengthScore
monsterDexterityScore = monster.dexterityScore
monsterConstitutionScore = monster.constitutionScore
monsterIntelligenceScore = monster.intelligenceScore
monsterWisdomScore = monster.wisdomScore
monsterCharismaScore = monster.charismaScore
monsterStrengthSavingThrowProficiency = ProficiencyType.init(rawValue: monster.strengthSavingThrowProficiency ?? "") ?? .none
monsterStrengthSavingThrowAdvantage = AdvantageType(rawValue: monster.strengthSavingThrowAdvantage ?? "") ?? .none
monsterDexteritySavingThrowProficiency = ProficiencyType(rawValue: monster.dexteritySavingThrowProficiency ?? "") ?? .none
monsterDexteritySavingThrowAdvantage = AdvantageType(rawValue: monster.dexteritySavingThrowAdvantage ?? "") ?? .none
monsterConstitutionSavingThrowProficiency = ProficiencyType(rawValue: monster.constitutionSavingThrowProficiency ?? "") ?? .none
monsterConstitutionSavingThrowAdvantage = AdvantageType(rawValue: monster.constitutionSavingThrowAdvantage ?? "") ?? .none
monsterIntelligenceSavingThrowProficiency = ProficiencyType(rawValue: monster.intelligenceSavingThrowProficiency ?? "") ?? .none
monsterIntelligenceSavingThrowAdvantage = AdvantageType(rawValue: monster.intelligenceSavingThrowAdvantage ?? "") ?? .none
monsterWisdomSavingThrowProficiency = ProficiencyType(rawValue: monster.wisdomSavingThrowProficiency ?? "") ?? .none
monsterWisdomSavingThrowAdvantage = AdvantageType(rawValue: monster.wisdomSavingThrowAdvantage ?? "") ?? .none
monsterCharismaSavingThrowProficiency = ProficiencyType(rawValue: monster.charismaSavingThrowProficiency ?? "") ?? .none
monsterCharismaSavingThrowAdvantage = AdvantageType(rawValue: monster.charismaSavingThrowAdvantage ?? "") ?? .none
}
private func copyLocalToMonster() {
monster.name = monsterName
monster.size = monsterSize
monster.type = monsterType
monster.subtype = monsterSubtype
monster.alignment = monsterAlignment
monster.hitDice = monsterHitDice
monster.hasCustomHP = monsterHasCustomHP
monster.customHP = monsterCustomHP
monster.armorType = monsterArmorType.rawValue
monster.hasShield = monsterHasShield
monster.naturalArmorBonus = monsterNaturalArmorBonus
monster.customArmor = monsterCustomArmor
monster.baseSpeed = monsterBaseSpeed
monster.burrowSpeed = monsterBurrowSpeed
monster.climbSpeed = monsterClimbSpeed
monster.flySpeed = monsterFlySpeed
monster.canHover = monsterCanHover
monster.swimSpeed = monsterSwimSpeed
monster.hasCustomSpeed = monsterHasCustomSpeed
monster.customSpeed = monsterCustomSpeed
monster.strengthScore = monsterStrengthScore
monster.dexterityScore = monsterDexterityScore
monster.constitutionScore = monsterConstitutionScore
monster.intelligenceScore = monsterIntelligenceScore
monster.wisdomScore = monsterWisdomScore
monster.charismaScore = monsterCharismaScore
monster.strengthSavingThrowProficiency = monsterStrengthSavingThrowProficiency.rawValue
monster.strengthSavingThrowAdvantage = monsterStrengthSavingThrowAdvantage.rawValue
monster.dexteritySavingThrowProficiency = monsterDexteritySavingThrowProficiency.rawValue
monster.dexteritySavingThrowAdvantage = monsterDexteritySavingThrowAdvantage.rawValue
monster.constitutionSavingThrowProficiency = monsterConstitutionSavingThrowProficiency.rawValue
monster.constitutionSavingThrowAdvantage = monsterConstitutionSavingThrowAdvantage.rawValue
monster.intelligenceSavingThrowProficiency = monsterIntelligenceSavingThrowProficiency.rawValue
monster.intelligenceSavingThrowAdvantage = monsterIntelligenceSavingThrowAdvantage.rawValue
monster.wisdomSavingThrowProficiency = monsterWisdomSavingThrowProficiency.rawValue
monster.wisdomSavingThrowAdvantage = monsterWisdomSavingThrowAdvantage.rawValue
monster.charismaSavingThrowProficiency = monsterCharismaSavingThrowProficiency.rawValue
monster.charismaSavingThrowAdvantage = monsterCharismaSavingThrowAdvantage.rawValue
}
}
struct EditMonster_Previews: PreviewProvider {
static var previews: some View {
let context = PersistenceController.preview.container.viewContext
let monster = Monster.init(context: context)
monster.name = "Steve"
monster.size = "Medium"
monster.type = "humanoid"
monster.subtype = "human"
monster.alignment = "LG"
monster.hitDice = 6
monster.hasCustomHP = true
monster.customHP = "12 (1d10)+2"
monster.baseSpeed = 5
monster.burrowSpeed = 10
monster.climbSpeed = 15
monster.flySpeed = 20
monster.swimSpeed = 25
monster.canHover = true
monster.hasCustomSpeed = false
monster.customSpeed = "walk: 5 ft."
monster.strengthScore = 8
monster.dexterityScore = 10
monster.constitutionScore = 12
monster.intelligenceScore = 14
monster.wisdomScore = 16
monster.charismaScore = 18
monster.strengthSavingThrowAdvantage = AdvantageType.none.rawValue
monster.strengthSavingThrowProficiency = ProficiencyType.none.rawValue
monster.dexteritySavingThrowAdvantage = AdvantageType.advantage.rawValue
monster.dexteritySavingThrowProficiency = ProficiencyType.proficient.rawValue
monster.constitutionSavingThrowAdvantage = AdvantageType.disadvantage.rawValue
monster.constitutionSavingThrowProficiency = ProficiencyType.expertise.rawValue
monster.intelligenceSavingThrowAdvantage = AdvantageType.none.rawValue
monster.intelligenceSavingThrowProficiency = ProficiencyType.expertise.rawValue
monster.wisdomSavingThrowAdvantage = AdvantageType.advantage.rawValue
monster.wisdomSavingThrowProficiency = ProficiencyType.proficient.rawValue
monster.charismaSavingThrowAdvantage = AdvantageType.disadvantage.rawValue
monster.charismaSavingThrowProficiency = ProficiencyType.none.rawValue
return EditMonster(monster: monster).environment(\.managedObjectContext, context)
}
}