Adds MarkdownUI dependency and abilities.
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 50;
|
||||
objectVersion = 52;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
@@ -28,6 +28,10 @@
|
||||
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 */; };
|
||||
E254F901260D07C1009295A5 /* MarkdownUI in Frameworks */ = {isa = PBXBuildFile; productRef = E254F900260D07C1009295A5 /* MarkdownUI */; };
|
||||
E254F906260D0818009295A5 /* AbilityViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E254F905260D0818009295A5 /* AbilityViewModel.swift */; };
|
||||
E254F90E260D19A0009295A5 /* EditAbilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = E254F90D260D19A0009295A5 /* EditAbilities.swift */; };
|
||||
E254F913260D1F6D009295A5 /* EditAbility.swift in Sources */ = {isa = PBXBuildFile; fileRef = E254F912260D1F6D009295A5 /* EditAbility.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 */; };
|
||||
@@ -96,6 +100,9 @@
|
||||
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>"; };
|
||||
E254F905260D0818009295A5 /* AbilityViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AbilityViewModel.swift; sourceTree = "<group>"; };
|
||||
E254F90D260D19A0009295A5 /* EditAbilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditAbilities.swift; sourceTree = "<group>"; };
|
||||
E254F912260D1F6D009295A5 /* EditAbility.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditAbility.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>"; };
|
||||
@@ -136,6 +143,7 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
E254F901260D07C1009295A5 /* MarkdownUI in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -237,6 +245,8 @@
|
||||
E2570FF925B1AE020055B23B /* Collections.swift */,
|
||||
E2570FBA25B1AC520055B23B /* ContentView.swift */,
|
||||
E2570FF425B1ADEB0055B23B /* Dashboard.swift */,
|
||||
E254F90D260D19A0009295A5 /* EditAbilities.swift */,
|
||||
E254F912260D1F6D009295A5 /* EditAbility.swift */,
|
||||
E24ACE5F2607F45E009BF703 /* EditAbilityScores.swift */,
|
||||
E24ACE552607EE94009BF703 /* EditArmor.swift */,
|
||||
E24ACE4F2607326E009BF703 /* EditBasicInfo.swift */,
|
||||
@@ -267,6 +277,7 @@
|
||||
E257101225B1B2790055B23B /* Models */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E254F905260D0818009295A5 /* AbilityViewModel.swift */,
|
||||
E216B7B6260C5A9800FB205F /* ChallengeRatingViewModel.swift */,
|
||||
E20209E625D8DEB600EFE733 /* Enums */,
|
||||
E216B790260C1FE800FB205F /* LanguageViewModel.swift */,
|
||||
@@ -304,6 +315,9 @@
|
||||
dependencies = (
|
||||
);
|
||||
name = MonsterCards;
|
||||
packageProductDependencies = (
|
||||
E254F900260D07C1009295A5 /* MarkdownUI */,
|
||||
);
|
||||
productName = MonsterCards;
|
||||
productReference = E2570FB525B1AC520055B23B /* MonsterCards.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
@@ -375,6 +389,9 @@
|
||||
Base,
|
||||
);
|
||||
mainGroup = E2570FAC25B1AC520055B23B;
|
||||
packageReferences = (
|
||||
E254F8FF260D07C1009295A5 /* XCRemoteSwiftPackageReference "MarkdownUI" */,
|
||||
);
|
||||
productRefGroup = E2570FB625B1AC520055B23B /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
@@ -423,6 +440,7 @@
|
||||
E216B799260C2DF200FB205F /* EditLanguages.swift in Sources */,
|
||||
E2570FBB25B1AC520055B23B /* ContentView.swift in Sources */,
|
||||
E24ACE502607326E009BF703 /* EditBasicInfo.swift in Sources */,
|
||||
E254F90E260D19A0009295A5 /* EditAbilities.swift in Sources */,
|
||||
E2570FC525B1AC550055B23B /* MonsterCards.xcdatamodeld in Sources */,
|
||||
E2182E6425B22F8A00DFAEF8 /* Monster+CoreDataClass.swift in Sources */,
|
||||
E216B791260C1FE800FB205F /* LanguageViewModel.swift in Sources */,
|
||||
@@ -449,9 +467,11 @@
|
||||
E2CB0DE1260887ED00142591 /* StringViewModel.swift in Sources */,
|
||||
E20209F425D8E04300EFE733 /* ProficiencyType.swift in Sources */,
|
||||
E2CB0DC526086E5F00142591 /* SizeType.swift in Sources */,
|
||||
E254F906260D0818009295A5 /* AbilityViewModel.swift in Sources */,
|
||||
E2570FFA25B1AE020055B23B /* Collections.swift in Sources */,
|
||||
E24ACE5B2607F0F2009BF703 /* EditSpeed.swift in Sources */,
|
||||
E2570FB925B1AC520055B23B /* MonsterCardsApp.swift in Sources */,
|
||||
E254F913260D1F6D009295A5 /* EditAbility.swift in Sources */,
|
||||
E216B7B7260C5A9800FB205F /* ChallengeRatingViewModel.swift in Sources */,
|
||||
E20209D325D8DD9600EFE733 /* Skill+CoreDataClass.swift in Sources */,
|
||||
E24ACE652607F55D009BF703 /* EditSavingThrows.swift in Sources */,
|
||||
@@ -781,6 +801,25 @@
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
|
||||
/* Begin XCRemoteSwiftPackageReference section */
|
||||
E254F8FF260D07C1009295A5 /* XCRemoteSwiftPackageReference "MarkdownUI" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/gonzalezreal/MarkdownUI";
|
||||
requirement = {
|
||||
kind = upToNextMinorVersion;
|
||||
minimumVersion = 0.5.1;
|
||||
};
|
||||
};
|
||||
/* End XCRemoteSwiftPackageReference section */
|
||||
|
||||
/* Begin XCSwiftPackageProductDependency section */
|
||||
E254F900260D07C1009295A5 /* MarkdownUI */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = E254F8FF260D07C1009295A5 /* XCRemoteSwiftPackageReference "MarkdownUI" */;
|
||||
productName = MarkdownUI;
|
||||
};
|
||||
/* End XCSwiftPackageProductDependency section */
|
||||
|
||||
/* Begin XCVersionGroup section */
|
||||
E2570FC325B1AC550055B23B /* MonsterCards.xcdatamodeld */ = {
|
||||
isa = XCVersionGroup;
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
{
|
||||
"object": {
|
||||
"pins": [
|
||||
{
|
||||
"package": "AttributedText",
|
||||
"repositoryURL": "https://github.com/gonzalezreal/AttributedText",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "bf076de48dbb2172525486936d512e1bba062642",
|
||||
"version": "0.3.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "combine-schedulers",
|
||||
"repositoryURL": "https://github.com/pointfreeco/combine-schedulers",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "f1250faa1c1436ca83950ce676a4fe97a309a457",
|
||||
"version": "0.4.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "MarkdownUI",
|
||||
"repositoryURL": "https://github.com/gonzalezreal/MarkdownUI",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "e8931e37dcf777b4c03ca76aa09c10cf246a2ced",
|
||||
"version": "0.5.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "NetworkImage",
|
||||
"repositoryURL": "https://github.com/gonzalezreal/NetworkImage",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "15582b821cb097012b41b83d6219717926ec4ed6",
|
||||
"version": "2.1.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "cmark",
|
||||
"repositoryURL": "https://github.com/SwiftDocOrg/swift-cmark.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "9c8096a23f44794bde297452d87c455fc4f76d42",
|
||||
"version": "0.29.0+20210102.9c8096a"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "SwiftCommonMark",
|
||||
"repositoryURL": "https://github.com/gonzalezreal/SwiftCommonMark",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "f1575c37110a386e50da3208a04266b398bcefaa",
|
||||
"version": "0.1.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "xctest-dynamic-overlay",
|
||||
"repositoryURL": "https://github.com/pointfreeco/xctest-dynamic-overlay",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "603974e3909ad4b48ba04aad7e0ceee4f077a518",
|
||||
"version": "0.1.0"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": 1
|
||||
}
|
||||
@@ -4,6 +4,69 @@
|
||||
<dict>
|
||||
<key>SchemeUserState</key>
|
||||
<dict>
|
||||
<key>AttributedText_iOS (Playground) 1.xcscheme</key>
|
||||
<dict>
|
||||
<key>isShown</key>
|
||||
<false/>
|
||||
<key>orderHint</key>
|
||||
<integer>11</integer>
|
||||
</dict>
|
||||
<key>AttributedText_iOS (Playground) 2.xcscheme</key>
|
||||
<dict>
|
||||
<key>isShown</key>
|
||||
<false/>
|
||||
<key>orderHint</key>
|
||||
<integer>12</integer>
|
||||
</dict>
|
||||
<key>AttributedText_iOS (Playground).xcscheme</key>
|
||||
<dict>
|
||||
<key>isShown</key>
|
||||
<false/>
|
||||
<key>orderHint</key>
|
||||
<integer>10</integer>
|
||||
</dict>
|
||||
<key>AttributedText_macOS (Playground) 1.xcscheme</key>
|
||||
<dict>
|
||||
<key>isShown</key>
|
||||
<false/>
|
||||
<key>orderHint</key>
|
||||
<integer>8</integer>
|
||||
</dict>
|
||||
<key>AttributedText_macOS (Playground) 2.xcscheme</key>
|
||||
<dict>
|
||||
<key>isShown</key>
|
||||
<false/>
|
||||
<key>orderHint</key>
|
||||
<integer>9</integer>
|
||||
</dict>
|
||||
<key>AttributedText_macOS (Playground).xcscheme</key>
|
||||
<dict>
|
||||
<key>isShown</key>
|
||||
<false/>
|
||||
<key>orderHint</key>
|
||||
<integer>7</integer>
|
||||
</dict>
|
||||
<key>AttributedText_tvOS (Playground) 1.xcscheme</key>
|
||||
<dict>
|
||||
<key>isShown</key>
|
||||
<false/>
|
||||
<key>orderHint</key>
|
||||
<integer>14</integer>
|
||||
</dict>
|
||||
<key>AttributedText_tvOS (Playground) 2.xcscheme</key>
|
||||
<dict>
|
||||
<key>isShown</key>
|
||||
<false/>
|
||||
<key>orderHint</key>
|
||||
<integer>15</integer>
|
||||
</dict>
|
||||
<key>AttributedText_tvOS (Playground).xcscheme</key>
|
||||
<dict>
|
||||
<key>isShown</key>
|
||||
<false/>
|
||||
<key>orderHint</key>
|
||||
<integer>13</integer>
|
||||
</dict>
|
||||
<key>MonsterCards.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
|
||||
116
MonsterCards/Models/AbilityViewModel.swift
Normal file
116
MonsterCards/Models/AbilityViewModel.swift
Normal file
@@ -0,0 +1,116 @@
|
||||
//
|
||||
// AbilityViewModel.swift
|
||||
// MonsterCards
|
||||
//
|
||||
// Created by Tom Hicks on 3/25/21.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public class AbilityViewModel: NSObject, ObservableObject, Identifiable, NSSecureCoding {
|
||||
public static var supportsSecureCoding = true
|
||||
|
||||
public func encode(with coder: NSCoder) {
|
||||
coder.encode(self.name, forKey: "name")
|
||||
coder.encode(self.abilityDescription, forKey: "abilityDescription")
|
||||
}
|
||||
|
||||
public required init?(coder: NSCoder) {
|
||||
self.name = coder.decodeObject(of: NSString.self, forKey: "name")! as String
|
||||
self.abilityDescription = coder.decodeObject(of: NSString.self, forKey: "abilityDescription")! as String
|
||||
}
|
||||
|
||||
@Published public var name: String
|
||||
@Published public var abilityDescription: String
|
||||
|
||||
public init(_ name: String = "", _ abilityDescription: String = "") {
|
||||
self.name = name
|
||||
self.abilityDescription = abilityDescription
|
||||
}
|
||||
|
||||
public var fullText: String {
|
||||
get {
|
||||
return String(format: "___%@:___ %@", name, abilityDescription)
|
||||
}
|
||||
}
|
||||
|
||||
public func renderedText(_ monster: Monster) -> String {
|
||||
let strSave = monster.strengthModifier + monster.proficiencyBonus + 8
|
||||
let dexSave = monster.dexterityModifier + monster.proficiencyBonus + 8
|
||||
let conSave = monster.constitutionModifier + monster.proficiencyBonus + 8
|
||||
let intSave = monster.intelligenceModifier + monster.proficiencyBonus + 8
|
||||
let wisSave = monster.wisdomModifier + monster.proficiencyBonus + 8
|
||||
let chaSave = monster.charismaModifier + monster.proficiencyBonus + 8
|
||||
let strAttack = monster.strengthModifier + monster.proficiencyBonus
|
||||
let dexAttack = monster.dexterityModifier + monster.proficiencyBonus
|
||||
let conAttack = monster.constitutionModifier + monster.proficiencyBonus
|
||||
let intAttack = monster.intelligenceModifier + monster.proficiencyBonus
|
||||
let wisAttack = monster.wisdomModifier + monster.proficiencyBonus
|
||||
let chaAttack = monster.charismaModifier + monster.proficiencyBonus
|
||||
|
||||
// TODO: find the other options and implement them [WIS], [WIS STAT], [WIS DMG], [WIS STAT 1d12]
|
||||
|
||||
let finalText = fullText
|
||||
.replacingOccurrences(of: "[STR SAVE]", with: String(strSave))
|
||||
.replacingOccurrences(of: "[DEX SAVE]", with: String(dexSave))
|
||||
.replacingOccurrences(of: "[CON SAVE]", with: String(conSave))
|
||||
.replacingOccurrences(of: "[INT SAVE]", with: String(intSave))
|
||||
.replacingOccurrences(of: "[WIS SAVE]", with: String(wisSave))
|
||||
.replacingOccurrences(of: "[CHA SAVE]", with: String(chaSave))
|
||||
.replacingOccurrences(of: "[STR ATK]", with: String(strAttack))
|
||||
.replacingOccurrences(of: "[DEX ATK]", with: String(dexAttack))
|
||||
.replacingOccurrences(of: "[CON ATK]", with: String(conAttack))
|
||||
.replacingOccurrences(of: "[INT ATK]", with: String(intAttack))
|
||||
.replacingOccurrences(of: "[WIS ATK]", with: String(wisAttack))
|
||||
.replacingOccurrences(of: "[CHA ATK]", with: String(chaAttack))
|
||||
|
||||
return finalText
|
||||
}
|
||||
}
|
||||
|
||||
extension AbilityViewModel: Comparable {
|
||||
public static func < (lhs: AbilityViewModel, rhs: AbilityViewModel) -> Bool {
|
||||
lhs.name < rhs.name
|
||||
}
|
||||
|
||||
public static func == (lhs: AbilityViewModel, rhs: AbilityViewModel) -> Bool {
|
||||
lhs.name == rhs.name &&
|
||||
lhs.abilityDescription == rhs.abilityDescription
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: figure out how to add this to the set of known transformers so it will work with transformer set to NSSecureUnarchiveFromDataTransformerName
|
||||
@objc(AbilityViewModelValueTransformer)
|
||||
public final class AbilityViewModelValueTransformer: ValueTransformer {
|
||||
override public class func transformedValueClass() -> AnyClass {
|
||||
return NSArray.self
|
||||
}
|
||||
|
||||
override public class func allowsReverseTransformation() -> Bool {
|
||||
return true
|
||||
}
|
||||
|
||||
override public func transformedValue(_ value: Any?) -> Any? {
|
||||
guard let language = value as? NSArray else { return nil }
|
||||
|
||||
do {
|
||||
let data = try NSKeyedArchiver.archivedData(withRootObject: language, requiringSecureCoding: true)
|
||||
return data
|
||||
} catch {
|
||||
assertionFailure("Failed to transform `AbilityViewModel` to `Data`")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
override public func reverseTransformedValue(_ value: Any?) -> Any? {
|
||||
guard let data = value as? NSData else { return nil }
|
||||
|
||||
do {
|
||||
let language = try NSKeyedUnarchiver.unarchivedArrayOfObjects(ofClass: AbilityViewModel.self, from: data as Data)
|
||||
return language
|
||||
} catch {
|
||||
assertionFailure("Failed to transform `Data` to `AbilityViewModel`")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -60,6 +60,7 @@ class MonsterViewModel: ObservableObject {
|
||||
@Published var challengeRating: ChallengeRating
|
||||
@Published var customChallengeRating: String
|
||||
@Published var customProficiencyBonus: Int64
|
||||
@Published var abilities: [AbilityViewModel]
|
||||
|
||||
init(_ rawMonster: Monster? = nil) {
|
||||
self.name = ""
|
||||
@@ -112,6 +113,7 @@ class MonsterViewModel: ObservableObject {
|
||||
self.challengeRating = .one
|
||||
self.customChallengeRating = ""
|
||||
self.customProficiencyBonus = 0
|
||||
self.abilities = []
|
||||
|
||||
if (rawMonster != nil) {
|
||||
self.copyFromMonster(monster: rawMonster!)
|
||||
@@ -186,7 +188,12 @@ class MonsterViewModel: ObservableObject {
|
||||
.sorted()
|
||||
|
||||
self.languages = (monster.languages ?? [])
|
||||
.map {LanguageViewModel($0.name, $0.speaks)}
|
||||
.sorted()
|
||||
|
||||
// These are manually sorted in the UI
|
||||
self.abilities = (monster.abilities ?? [])
|
||||
.map {AbilityViewModel($0.name, $0.abilityDescription)}
|
||||
}
|
||||
|
||||
func copyToMonster(monster: Monster) {
|
||||
@@ -262,5 +269,7 @@ class MonsterViewModel: ObservableObject {
|
||||
|
||||
// This is necessary so core data sees the language objects as changed. Without it they won't be persisted.
|
||||
monster.languages = languages.map {LanguageViewModel($0.name, $0.speaks)}
|
||||
|
||||
monster.abilities = abilities.map {AbilityViewModel($0.name, $0.abilityDescription)}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="17709" systemVersion="20D91" minimumToolsVersion="Automatic" sourceLanguage="Swift" usedWithCloudKit="YES" userDefinedModelVersionIdentifier="">
|
||||
<entity name="Monster" representedClassName="Monster" syncable="YES" codeGenerationType="category">
|
||||
<attribute name="abilities" optional="YES" attributeType="Transformable" valueTransformerName="AbilityViewModelValueTransformer" customClassName="[AbilityViewModel]"/>
|
||||
<attribute name="alignment" attributeType="String" defaultValueString=""/>
|
||||
<attribute name="armorType" attributeType="String" defaultValueString=""/>
|
||||
<attribute name="baseSpeed" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
@@ -67,7 +68,7 @@
|
||||
<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="884"/>
|
||||
<element name="Monster" positionX="-63" positionY="-18" width="128" height="899"/>
|
||||
<element name="Skill" positionX="-63" positionY="135" width="128" height="14"/>
|
||||
</elements>
|
||||
</model>
|
||||
64
MonsterCards/Views/EditAbilities.swift
Normal file
64
MonsterCards/Views/EditAbilities.swift
Normal file
@@ -0,0 +1,64 @@
|
||||
//
|
||||
// EditAbilities.swift
|
||||
// MonsterCards
|
||||
//
|
||||
// Created by Tom Hicks on 3/25/21.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct EditAbilities: View {
|
||||
@ObservedObject var viewModel: MonsterViewModel
|
||||
var path: ReferenceWritableKeyPath<MonsterViewModel, [AbilityViewModel]>
|
||||
var title: String
|
||||
|
||||
var body: some View {
|
||||
List {
|
||||
ForEach(viewModel[keyPath: path]) { ability in
|
||||
NavigationLink(
|
||||
ability.name,
|
||||
destination: EditAbility(viewModel: ability))
|
||||
}
|
||||
.onDelete(perform: { indexSet in
|
||||
for index in indexSet {
|
||||
viewModel[keyPath: path].remove(at: index)
|
||||
}
|
||||
})
|
||||
.onMove(perform: { indices, newOffset in
|
||||
viewModel[keyPath: path].move(fromOffsets: indices, toOffset: newOffset)
|
||||
|
||||
})
|
||||
}
|
||||
.toolbar(content: {
|
||||
ToolbarItemGroup(placement: .navigationBarTrailing) {
|
||||
EditButton()
|
||||
|
||||
Button(
|
||||
action: {
|
||||
let newAbility = AbilityViewModel()
|
||||
viewModel[keyPath: path].append(newAbility)
|
||||
viewModel[keyPath: path] = viewModel[keyPath: path].sorted()
|
||||
},
|
||||
label: {
|
||||
Image(systemName: "plus")
|
||||
}
|
||||
)
|
||||
}
|
||||
})
|
||||
.onAppear(perform: {
|
||||
viewModel[keyPath: path] = viewModel[keyPath: path].sorted()
|
||||
})
|
||||
.navigationTitle(title)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
struct EditAbilities_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
let viewModel = MonsterViewModel()
|
||||
EditAbilities(
|
||||
viewModel: viewModel,
|
||||
path: \.abilities,
|
||||
title: "Abilities")
|
||||
}
|
||||
}
|
||||
29
MonsterCards/Views/EditAbility.swift
Normal file
29
MonsterCards/Views/EditAbility.swift
Normal file
@@ -0,0 +1,29 @@
|
||||
//
|
||||
// EditAbility.swift
|
||||
// MonsterCards
|
||||
//
|
||||
// Created by Tom Hicks on 3/25/21.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct EditAbility: View {
|
||||
@ObservedObject var viewModel: AbilityViewModel
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
MCTextField(
|
||||
label: "Name",
|
||||
value: $viewModel.name)
|
||||
|
||||
TextEditor(text: $viewModel.abilityDescription)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct EditAbility_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
let viewModel = AbilityViewModel()
|
||||
EditAbility(viewModel: viewModel)
|
||||
}
|
||||
}
|
||||
@@ -73,6 +73,9 @@ struct EditMonster: View {
|
||||
NavigationLink(
|
||||
"Challenge Rating",
|
||||
destination: EditChallengeRating(viewModel: monsterViewModel))
|
||||
|
||||
NavigationLink(
|
||||
"Abilities", destination: EditAbilities(viewModel: monsterViewModel, path: \.abilities, title: "Abilities"))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -33,8 +33,8 @@ struct EditStrings: View {
|
||||
.toolbar(content: {
|
||||
Button(
|
||||
action: {
|
||||
let newDamageType = StringViewModel()
|
||||
viewModel[keyPath: path].append(newDamageType)
|
||||
let newString = StringViewModel()
|
||||
viewModel[keyPath: path].append(newString)
|
||||
viewModel[keyPath: path] = viewModel[keyPath: path].sorted()
|
||||
},
|
||||
label: {
|
||||
@@ -44,13 +44,17 @@ struct EditStrings: View {
|
||||
})
|
||||
.onAppear(perform: {
|
||||
viewModel[keyPath: path] = viewModel[keyPath: path].sorted()
|
||||
}).navigationTitle(title)
|
||||
})
|
||||
.navigationTitle(title)
|
||||
}
|
||||
}
|
||||
|
||||
struct EditStrings_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
let viewModel = MonsterViewModel()
|
||||
EditStrings(viewModel: viewModel, path: \.damageImmunities, title: "Damage Types")
|
||||
EditStrings(
|
||||
viewModel: viewModel,
|
||||
path: \.damageImmunities,
|
||||
title: "Damage Types")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import MarkdownUI
|
||||
|
||||
struct LabeledField<Content: View>: View {
|
||||
@Environment(\.horizontalSizeClass) var sizeClass
|
||||
@@ -209,6 +210,7 @@ struct MonsterDetail: View {
|
||||
VStack (alignment: .leading) {
|
||||
let monsterLanguagesDescription = monster.languagesDescription
|
||||
let monsterChallengeRatingDescription = monster.challengeRatingDescription
|
||||
let monsterAbilities: [AbilityViewModel] = monster.abilities ?? []
|
||||
|
||||
BasicInfoView(monster: monster)
|
||||
|
||||
@@ -243,6 +245,14 @@ struct MonsterDetail: View {
|
||||
}
|
||||
|
||||
// Abilities
|
||||
if (monsterAbilities.count > 0) {
|
||||
ForEach(monsterAbilities) { ability in
|
||||
VStack {
|
||||
Markdown(Document(ability.renderedText(monster)/*.fullText*/))
|
||||
Divider()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Actions
|
||||
|
||||
|
||||
Reference in New Issue
Block a user