From 861bae24d6c13bc813e52e546ccb650391a956c2 Mon Sep 17 00:00:00 2001 From: Tom Hicks Date: Sun, 21 Mar 2021 16:18:04 -0700 Subject: [PATCH] Adds EditSkills view bound to the monster view model's skills. --- iOS/EditSkills.swift | 44 ++++++++ iOS/MonsterCards.xcodeproj/project.pbxproj | 4 + .../Models/MonsterViewModel.swift | 20 ++-- .../Models/Skill+CoreDataClass.swift | 9 ++ iOS/MonsterCards/Models/SkillViewModel.swift | 103 +++++++++++++++++- .../MonsterCards.xcdatamodel/contents | 9 +- iOS/MonsterCards/Views/EditMonster.swift | 4 + 7 files changed, 178 insertions(+), 15 deletions(-) create mode 100644 iOS/EditSkills.swift diff --git a/iOS/EditSkills.swift b/iOS/EditSkills.swift new file mode 100644 index 0000000..e3ec815 --- /dev/null +++ b/iOS/EditSkills.swift @@ -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) + } +} diff --git a/iOS/MonsterCards.xcodeproj/project.pbxproj b/iOS/MonsterCards.xcodeproj/project.pbxproj index 9f2ade3..f7f9b66 100644 --- a/iOS/MonsterCards.xcodeproj/project.pbxproj +++ b/iOS/MonsterCards.xcodeproj/project.pbxproj @@ -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 = ""; }; E24ACE5F2607F45E009BF703 /* EditAbilityScores.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditAbilityScores.swift; sourceTree = ""; }; E24ACE642607F55D009BF703 /* EditSavingThrows.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditSavingThrows.swift; sourceTree = ""; }; + E24ACE692607F715009BF703 /* EditSkills.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditSkills.swift; sourceTree = ""; }; 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 = ""; }; E2570FBA25B1AC520055B23B /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; @@ -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 */, diff --git a/iOS/MonsterCards/Models/MonsterViewModel.swift b/iOS/MonsterCards/Models/MonsterViewModel.swift index 3890262..053fef4 100644 --- a/iOS/MonsterCards/Models/MonsterViewModel.swift +++ b/iOS/MonsterCards/Models/MonsterViewModel.swift @@ -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( diff --git a/iOS/MonsterCards/Models/Skill+CoreDataClass.swift b/iOS/MonsterCards/Models/Skill+CoreDataClass.swift index b1dd446..11420fd 100644 --- a/iOS/MonsterCards/Models/Skill+CoreDataClass.swift +++ b/iOS/MonsterCards/Models/Skill+CoreDataClass.swift @@ -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) diff --git a/iOS/MonsterCards/Models/SkillViewModel.swift b/iOS/MonsterCards/Models/SkillViewModel.swift index 4cae7bd..29c7f86 100644 --- a/iOS/MonsterCards/Models/SkillViewModel.swift +++ b/iOS/MonsterCards/Models/SkillViewModel.swift @@ -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 + } } diff --git a/iOS/MonsterCards/MonsterCards.xcdatamodeld/MonsterCards.xcdatamodel/contents b/iOS/MonsterCards/MonsterCards.xcdatamodeld/MonsterCards.xcdatamodel/contents index 4a9c924..395c54f 100644 --- a/iOS/MonsterCards/MonsterCards.xcdatamodeld/MonsterCards.xcdatamodel/contents +++ b/iOS/MonsterCards/MonsterCards.xcdatamodeld/MonsterCards.xcdatamodel/contents @@ -1,5 +1,5 @@ - + @@ -52,13 +52,14 @@ - + + - + - + \ No newline at end of file diff --git a/iOS/MonsterCards/Views/EditMonster.swift b/iOS/MonsterCards/Views/EditMonster.swift index ac9a634..b126b01 100644 --- a/iOS/MonsterCards/Views/EditMonster.swift +++ b/iOS/MonsterCards/Views/EditMonster.swift @@ -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: {