Adds EditSkills view bound to the monster view model's skills.
This commit is contained in:
44
EditSkills.swift
Normal file
44
EditSkills.swift
Normal file
@@ -0,0 +1,44 @@
|
||||
//
|
||||
// EditSkills.swift
|
||||
// MonsterCards
|
||||
//
|
||||
// Created by Tom Hicks on 3/21/21.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct EditSkills: View {
|
||||
@ObservedObject var monsterViewModel: MonsterViewModel
|
||||
|
||||
var body: some View {
|
||||
List {
|
||||
ForEach(monsterViewModel.skills, id: \.self) { skill in
|
||||
Text(skill.name)
|
||||
}
|
||||
.onDelete(perform: { indexSet in
|
||||
for index in indexSet {
|
||||
monsterViewModel.skills.remove(at: index)
|
||||
}
|
||||
})
|
||||
}
|
||||
.toolbar(content: {
|
||||
Button(
|
||||
action: {
|
||||
let newSkill = SkillViewModel(nil)
|
||||
newSkill.name = "New Skill"
|
||||
monsterViewModel.skills.append(newSkill)
|
||||
},
|
||||
label: {
|
||||
Image(systemName: "plus")
|
||||
}
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
struct EditSkills_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
let viewModel = MonsterViewModel(nil)
|
||||
EditSkills(monsterViewModel: viewModel)
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,7 @@
|
||||
E24ACE5B2607F0F2009BF703 /* EditSpeed.swift in Sources */ = {isa = PBXBuildFile; fileRef = E24ACE5A2607F0F2009BF703 /* EditSpeed.swift */; };
|
||||
E24ACE602607F45E009BF703 /* EditAbilityScores.swift in Sources */ = {isa = PBXBuildFile; fileRef = E24ACE5F2607F45E009BF703 /* EditAbilityScores.swift */; };
|
||||
E24ACE652607F55D009BF703 /* EditSavingThrows.swift in Sources */ = {isa = PBXBuildFile; fileRef = E24ACE642607F55D009BF703 /* EditSavingThrows.swift */; };
|
||||
E24ACE6A2607F715009BF703 /* EditSkills.swift in Sources */ = {isa = PBXBuildFile; fileRef = E24ACE692607F715009BF703 /* EditSkills.swift */; };
|
||||
E2570FB925B1AC520055B23B /* MonsterCardsApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2570FB825B1AC520055B23B /* MonsterCardsApp.swift */; };
|
||||
E2570FBB25B1AC520055B23B /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2570FBA25B1AC520055B23B /* ContentView.swift */; };
|
||||
E2570FBD25B1AC550055B23B /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E2570FBC25B1AC550055B23B /* Assets.xcassets */; };
|
||||
@@ -74,6 +75,7 @@
|
||||
E24ACE5A2607F0F2009BF703 /* EditSpeed.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditSpeed.swift; sourceTree = "<group>"; };
|
||||
E24ACE5F2607F45E009BF703 /* EditAbilityScores.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditAbilityScores.swift; sourceTree = "<group>"; };
|
||||
E24ACE642607F55D009BF703 /* EditSavingThrows.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditSavingThrows.swift; sourceTree = "<group>"; };
|
||||
E24ACE692607F715009BF703 /* EditSkills.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditSkills.swift; sourceTree = "<group>"; };
|
||||
E2570FB525B1AC520055B23B /* MonsterCards.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MonsterCards.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
E2570FB825B1AC520055B23B /* MonsterCardsApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MonsterCardsApp.swift; sourceTree = "<group>"; };
|
||||
E2570FBA25B1AC520055B23B /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
|
||||
@@ -139,6 +141,7 @@
|
||||
E2570FAC25B1AC520055B23B = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E24ACE692607F715009BF703 /* EditSkills.swift */,
|
||||
E24ACE642607F55D009BF703 /* EditSavingThrows.swift */,
|
||||
E24ACE5F2607F45E009BF703 /* EditAbilityScores.swift */,
|
||||
E24ACE552607EE94009BF703 /* EditArmor.swift */,
|
||||
@@ -387,6 +390,7 @@
|
||||
E2570FF525B1ADEB0055B23B /* Dashboard.swift in Sources */,
|
||||
E257100425B1AF4A0055B23B /* SearchBar.swift in Sources */,
|
||||
E20209F525D8E04300EFE733 /* AdvantageType.swift in Sources */,
|
||||
E24ACE6A2607F715009BF703 /* EditSkills.swift in Sources */,
|
||||
E20209FC25D8E19100EFE733 /* MonsterViewModel.swift in Sources */,
|
||||
E2570FFF25B1AE180055B23B /* Library.swift in Sources */,
|
||||
E2BD703125B3BBB90058ED69 /* MCStepperField.swift in Sources */,
|
||||
|
||||
@@ -181,16 +181,16 @@ class MonsterViewModel: ObservableObject {
|
||||
monster.charismaSavingThrowAdvantageEnum = charismaSavingThrowAdvantage
|
||||
monster.charismaSavingThrowProficiencyEnum = charismaSavingThrowProficiency
|
||||
|
||||
// // Remove missing skills from raw monster
|
||||
// monster.skills?.forEach {s in
|
||||
// let skill = s as! Skill
|
||||
// let skillVM = skills.first { $0.isEqualTo(rawSkill: skill) }
|
||||
// if (skillVM != nil) {
|
||||
// skillVM!.copyToSkill(skill: skill)
|
||||
// } else {
|
||||
// monster.removeFromSkills(skill)
|
||||
// }
|
||||
// }
|
||||
// Remove missing skills from raw monster
|
||||
monster.skills?.forEach {s in
|
||||
let skill = s as! Skill
|
||||
let skillVM = skills.first { $0.isEqualTo(rawSkill: skill) }
|
||||
if (skillVM != nil) {
|
||||
skillVM!.copyToSkill(skill: skill)
|
||||
} else {
|
||||
monster.removeFromSkills(skill)
|
||||
}
|
||||
}
|
||||
// // Add new skills to raw monster
|
||||
// skills.forEach {skillVM in
|
||||
// if (!(monster.skills?.contains(
|
||||
|
||||
@@ -40,6 +40,15 @@ public class Skill: NSManagedObject {
|
||||
}
|
||||
}
|
||||
|
||||
var wrappedAdvantage: AdvantageType {
|
||||
get {
|
||||
return AdvantageType.init(rawValue: advantage ?? "") ?? .none
|
||||
}
|
||||
set {
|
||||
advantage = newValue.rawValue
|
||||
}
|
||||
}
|
||||
|
||||
var modifier: Int64 {
|
||||
get {
|
||||
let proficiencyBonus = Double(monster?.proficiencyBonus ?? 0)
|
||||
|
||||
@@ -6,15 +6,59 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreData
|
||||
|
||||
class SkillViewModel: ObservableObject {
|
||||
class SkillViewModel: ObservableObject, Hashable, Identifiable {
|
||||
static func == (lhs: SkillViewModel, rhs: SkillViewModel) -> Bool {
|
||||
return lhs.abilityScore == rhs.abilityScore
|
||||
&& lhs.advantage == rhs.advantage
|
||||
&& lhs.name == rhs.name
|
||||
&& lhs.proficiency == rhs.proficiency
|
||||
}
|
||||
|
||||
func hash(into hasher: inout Hasher) {
|
||||
hasher.combine(abilityScore)
|
||||
hasher.combine(advantage)
|
||||
hasher.combine(name)
|
||||
hasher.combine(proficiency)
|
||||
}
|
||||
|
||||
func isEqualTo(rawSkill: Skill?) -> Bool {
|
||||
if (rawSkill == nil) {
|
||||
return false;
|
||||
} else if (abilityScore != rawSkill!.wrappedAbilityScore) {
|
||||
return false;
|
||||
} else if (advantage != rawSkill!.wrappedAdvantage) {
|
||||
return false;
|
||||
} else if (name != rawSkill!.name) {
|
||||
return false;
|
||||
} else if (proficiency != rawSkill!.wrappedProficiency) {
|
||||
return false;
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
func copyToSkill(skill: Skill) {
|
||||
skill.wrappedAbilityScore = abilityScore
|
||||
skill.wrappedAdvantage = advantage
|
||||
skill.name = name
|
||||
skill.wrappedProficiency = proficiency
|
||||
}
|
||||
|
||||
init(_ rawSkill: Skill?) {
|
||||
if (rawSkill != nil) {
|
||||
self.rawSkill = rawSkill
|
||||
_name = rawSkill!.name ?? ""
|
||||
_abilityScore = AbilityScore(rawValue: rawSkill!.abilityScoreName ?? "") ?? .strength
|
||||
_proficiency = ProficiencyType(rawValue: rawSkill!.proficiency ?? "") ?? .none
|
||||
_advantage = AdvantageType(rawValue: rawSkill!.advantage ?? "") ?? .none
|
||||
_advantage = .none
|
||||
} else {
|
||||
_name = ""
|
||||
_abilityScore = .strength
|
||||
_proficiency = .none
|
||||
_advantage = .none
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,4 +79,61 @@ class SkillViewModel: ObservableObject {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var _abilityScore: AbilityScore
|
||||
var abilityScore: AbilityScore {
|
||||
get {
|
||||
return _abilityScore
|
||||
}
|
||||
set {
|
||||
if (newValue != _abilityScore) {
|
||||
_abilityScore = newValue
|
||||
// Notify changed
|
||||
}
|
||||
if (rawSkill != nil) {
|
||||
rawSkill!.wrappedAbilityScore = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var _proficiency: ProficiencyType
|
||||
var proficiency: ProficiencyType {
|
||||
get {
|
||||
return _proficiency
|
||||
}
|
||||
set {
|
||||
if (newValue != _proficiency) {
|
||||
_proficiency = newValue
|
||||
// Notify changed
|
||||
}
|
||||
if (rawSkill != nil) {
|
||||
rawSkill!.wrappedProficiency = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var _advantage: AdvantageType
|
||||
var advantage: AdvantageType {
|
||||
get {
|
||||
return _advantage
|
||||
}
|
||||
set {
|
||||
if (newValue != _advantage) {
|
||||
_advantage = newValue
|
||||
// Notify changed
|
||||
}
|
||||
if (rawSkill != nil) {
|
||||
rawSkill!.wrappedAdvantage = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func buildRawSkill(context: NSManagedObjectContext?) -> Skill {
|
||||
let newSkill = context == nil ? Skill.init() : Skill.init(context: context!)
|
||||
newSkill.name = name
|
||||
newSkill.wrappedAbilityScore = abilityScore
|
||||
newSkill.wrappedProficiency = proficiency
|
||||
newSkill.wrappedAdvantage = advantage
|
||||
return newSkill
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="17192" systemVersion="19H114" minimumToolsVersion="Automatic" sourceLanguage="Swift" usedWithCloudKit="YES" userDefinedModelVersionIdentifier="">
|
||||
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="17709" systemVersion="20D74" minimumToolsVersion="Automatic" sourceLanguage="Swift" usedWithCloudKit="YES" userDefinedModelVersionIdentifier="">
|
||||
<entity name="Monster" representedClassName="Monster" syncable="YES" codeGenerationType="category">
|
||||
<attribute name="alignment" attributeType="String" defaultValueString=""/>
|
||||
<attribute name="armorType" attributeType="String" defaultValueString=""/>
|
||||
@@ -52,13 +52,14 @@
|
||||
<relationship name="skills" optional="YES" toMany="YES" deletionRule="Cascade" destinationEntity="Skill" inverseName="monster" inverseEntity="Skill"/>
|
||||
</entity>
|
||||
<entity name="Skill" representedClassName="Skill" syncable="YES" codeGenerationType="category">
|
||||
<attribute name="abilityScoreName" attributeType="String" defaultValueString=""/>
|
||||
<attribute name="abilityScoreName" attributeType="String" defaultValueString="strength"/>
|
||||
<attribute name="advantage" attributeType="String" defaultValueString="none"/>
|
||||
<attribute name="name" attributeType="String" defaultValueString=""/>
|
||||
<attribute name="proficiency" attributeType="String" defaultValueString=""/>
|
||||
<attribute name="proficiency" attributeType="String" defaultValueString="none"/>
|
||||
<relationship name="monster" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Monster" inverseName="skills" inverseEntity="Monster"/>
|
||||
</entity>
|
||||
<elements>
|
||||
<element name="Monster" positionX="-63" positionY="-18" width="128" height="778"/>
|
||||
<element name="Skill" positionX="-63" positionY="135" width="128" height="103"/>
|
||||
<element name="Skill" positionX="-63" positionY="135" width="128" height="14"/>
|
||||
</elements>
|
||||
</model>
|
||||
@@ -39,6 +39,10 @@ struct EditMonster: View {
|
||||
NavigationLink(
|
||||
"Saving Throws",
|
||||
destination: EditSavingThrows(monsterViewModel: monsterViewModel))
|
||||
|
||||
NavigationLink(
|
||||
"Skills",
|
||||
destination: EditSkills(monsterViewModel: monsterViewModel))
|
||||
}
|
||||
.onAppear(perform: copyMonsterToLocal)
|
||||
.toolbar(content: {
|
||||
|
||||
Reference in New Issue
Block a user