Adds EditSkills view bound to the monster view model's skills.
This commit is contained in:
44
iOS/EditSkills.swift
Normal file
44
iOS/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 */; };
|
E24ACE5B2607F0F2009BF703 /* EditSpeed.swift in Sources */ = {isa = PBXBuildFile; fileRef = E24ACE5A2607F0F2009BF703 /* EditSpeed.swift */; };
|
||||||
E24ACE602607F45E009BF703 /* EditAbilityScores.swift in Sources */ = {isa = PBXBuildFile; fileRef = E24ACE5F2607F45E009BF703 /* EditAbilityScores.swift */; };
|
E24ACE602607F45E009BF703 /* EditAbilityScores.swift in Sources */ = {isa = PBXBuildFile; fileRef = E24ACE5F2607F45E009BF703 /* EditAbilityScores.swift */; };
|
||||||
E24ACE652607F55D009BF703 /* EditSavingThrows.swift in Sources */ = {isa = PBXBuildFile; fileRef = E24ACE642607F55D009BF703 /* EditSavingThrows.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 */; };
|
E2570FB925B1AC520055B23B /* MonsterCardsApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2570FB825B1AC520055B23B /* MonsterCardsApp.swift */; };
|
||||||
E2570FBB25B1AC520055B23B /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2570FBA25B1AC520055B23B /* ContentView.swift */; };
|
E2570FBB25B1AC520055B23B /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2570FBA25B1AC520055B23B /* ContentView.swift */; };
|
||||||
E2570FBD25B1AC550055B23B /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E2570FBC25B1AC550055B23B /* Assets.xcassets */; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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; };
|
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>"; };
|
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>"; };
|
E2570FBA25B1AC520055B23B /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
|
||||||
@@ -139,6 +141,7 @@
|
|||||||
E2570FAC25B1AC520055B23B = {
|
E2570FAC25B1AC520055B23B = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
E24ACE692607F715009BF703 /* EditSkills.swift */,
|
||||||
E24ACE642607F55D009BF703 /* EditSavingThrows.swift */,
|
E24ACE642607F55D009BF703 /* EditSavingThrows.swift */,
|
||||||
E24ACE5F2607F45E009BF703 /* EditAbilityScores.swift */,
|
E24ACE5F2607F45E009BF703 /* EditAbilityScores.swift */,
|
||||||
E24ACE552607EE94009BF703 /* EditArmor.swift */,
|
E24ACE552607EE94009BF703 /* EditArmor.swift */,
|
||||||
@@ -387,6 +390,7 @@
|
|||||||
E2570FF525B1ADEB0055B23B /* Dashboard.swift in Sources */,
|
E2570FF525B1ADEB0055B23B /* Dashboard.swift in Sources */,
|
||||||
E257100425B1AF4A0055B23B /* SearchBar.swift in Sources */,
|
E257100425B1AF4A0055B23B /* SearchBar.swift in Sources */,
|
||||||
E20209F525D8E04300EFE733 /* AdvantageType.swift in Sources */,
|
E20209F525D8E04300EFE733 /* AdvantageType.swift in Sources */,
|
||||||
|
E24ACE6A2607F715009BF703 /* EditSkills.swift in Sources */,
|
||||||
E20209FC25D8E19100EFE733 /* MonsterViewModel.swift in Sources */,
|
E20209FC25D8E19100EFE733 /* MonsterViewModel.swift in Sources */,
|
||||||
E2570FFF25B1AE180055B23B /* Library.swift in Sources */,
|
E2570FFF25B1AE180055B23B /* Library.swift in Sources */,
|
||||||
E2BD703125B3BBB90058ED69 /* MCStepperField.swift in Sources */,
|
E2BD703125B3BBB90058ED69 /* MCStepperField.swift in Sources */,
|
||||||
|
|||||||
@@ -181,16 +181,16 @@ class MonsterViewModel: ObservableObject {
|
|||||||
monster.charismaSavingThrowAdvantageEnum = charismaSavingThrowAdvantage
|
monster.charismaSavingThrowAdvantageEnum = charismaSavingThrowAdvantage
|
||||||
monster.charismaSavingThrowProficiencyEnum = charismaSavingThrowProficiency
|
monster.charismaSavingThrowProficiencyEnum = charismaSavingThrowProficiency
|
||||||
|
|
||||||
// // Remove missing skills from raw monster
|
// Remove missing skills from raw monster
|
||||||
// monster.skills?.forEach {s in
|
monster.skills?.forEach {s in
|
||||||
// let skill = s as! Skill
|
let skill = s as! Skill
|
||||||
// let skillVM = skills.first { $0.isEqualTo(rawSkill: skill) }
|
let skillVM = skills.first { $0.isEqualTo(rawSkill: skill) }
|
||||||
// if (skillVM != nil) {
|
if (skillVM != nil) {
|
||||||
// skillVM!.copyToSkill(skill: skill)
|
skillVM!.copyToSkill(skill: skill)
|
||||||
// } else {
|
} else {
|
||||||
// monster.removeFromSkills(skill)
|
monster.removeFromSkills(skill)
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// // Add new skills to raw monster
|
// // Add new skills to raw monster
|
||||||
// skills.forEach {skillVM in
|
// skills.forEach {skillVM in
|
||||||
// if (!(monster.skills?.contains(
|
// 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 {
|
var modifier: Int64 {
|
||||||
get {
|
get {
|
||||||
let proficiencyBonus = Double(monster?.proficiencyBonus ?? 0)
|
let proficiencyBonus = Double(monster?.proficiencyBonus ?? 0)
|
||||||
|
|||||||
@@ -6,15 +6,59 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
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?) {
|
init(_ rawSkill: Skill?) {
|
||||||
if (rawSkill != nil) {
|
if (rawSkill != nil) {
|
||||||
self.rawSkill = rawSkill
|
self.rawSkill = rawSkill
|
||||||
_name = rawSkill!.name ?? ""
|
_name = rawSkill!.name ?? ""
|
||||||
|
_abilityScore = AbilityScore(rawValue: rawSkill!.abilityScoreName ?? "") ?? .strength
|
||||||
|
_proficiency = ProficiencyType(rawValue: rawSkill!.proficiency ?? "") ?? .none
|
||||||
|
_advantage = AdvantageType(rawValue: rawSkill!.advantage ?? "") ?? .none
|
||||||
|
_advantage = .none
|
||||||
} else {
|
} else {
|
||||||
_name = ""
|
_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"?>
|
<?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">
|
<entity name="Monster" representedClassName="Monster" syncable="YES" codeGenerationType="category">
|
||||||
<attribute name="alignment" attributeType="String" defaultValueString=""/>
|
<attribute name="alignment" attributeType="String" defaultValueString=""/>
|
||||||
<attribute name="armorType" 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"/>
|
<relationship name="skills" optional="YES" toMany="YES" deletionRule="Cascade" destinationEntity="Skill" inverseName="monster" inverseEntity="Skill"/>
|
||||||
</entity>
|
</entity>
|
||||||
<entity name="Skill" representedClassName="Skill" syncable="YES" codeGenerationType="category">
|
<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="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"/>
|
<relationship name="monster" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Monster" inverseName="skills" inverseEntity="Monster"/>
|
||||||
</entity>
|
</entity>
|
||||||
<elements>
|
<elements>
|
||||||
<element name="Monster" positionX="-63" positionY="-18" width="128" height="778"/>
|
<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>
|
</elements>
|
||||||
</model>
|
</model>
|
||||||
@@ -39,6 +39,10 @@ struct EditMonster: View {
|
|||||||
NavigationLink(
|
NavigationLink(
|
||||||
"Saving Throws",
|
"Saving Throws",
|
||||||
destination: EditSavingThrows(monsterViewModel: monsterViewModel))
|
destination: EditSavingThrows(monsterViewModel: monsterViewModel))
|
||||||
|
|
||||||
|
NavigationLink(
|
||||||
|
"Skills",
|
||||||
|
destination: EditSkills(monsterViewModel: monsterViewModel))
|
||||||
}
|
}
|
||||||
.onAppear(perform: copyMonsterToLocal)
|
.onAppear(perform: copyMonsterToLocal)
|
||||||
.toolbar(content: {
|
.toolbar(content: {
|
||||||
|
|||||||
Reference in New Issue
Block a user