Adds MarkdownUI dependency and abilities.
This commit is contained in:
@@ -3,7 +3,7 @@
|
|||||||
archiveVersion = 1;
|
archiveVersion = 1;
|
||||||
classes = {
|
classes = {
|
||||||
};
|
};
|
||||||
objectVersion = 50;
|
objectVersion = 52;
|
||||||
objects = {
|
objects = {
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
@@ -28,6 +28,10 @@
|
|||||||
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 */; };
|
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 */; };
|
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 */; };
|
||||||
@@ -96,6 +100,9 @@
|
|||||||
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>"; };
|
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; };
|
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>"; };
|
||||||
@@ -136,6 +143,7 @@
|
|||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
E254F901260D07C1009295A5 /* MarkdownUI in Frameworks */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@@ -237,6 +245,8 @@
|
|||||||
E2570FF925B1AE020055B23B /* Collections.swift */,
|
E2570FF925B1AE020055B23B /* Collections.swift */,
|
||||||
E2570FBA25B1AC520055B23B /* ContentView.swift */,
|
E2570FBA25B1AC520055B23B /* ContentView.swift */,
|
||||||
E2570FF425B1ADEB0055B23B /* Dashboard.swift */,
|
E2570FF425B1ADEB0055B23B /* Dashboard.swift */,
|
||||||
|
E254F90D260D19A0009295A5 /* EditAbilities.swift */,
|
||||||
|
E254F912260D1F6D009295A5 /* EditAbility.swift */,
|
||||||
E24ACE5F2607F45E009BF703 /* EditAbilityScores.swift */,
|
E24ACE5F2607F45E009BF703 /* EditAbilityScores.swift */,
|
||||||
E24ACE552607EE94009BF703 /* EditArmor.swift */,
|
E24ACE552607EE94009BF703 /* EditArmor.swift */,
|
||||||
E24ACE4F2607326E009BF703 /* EditBasicInfo.swift */,
|
E24ACE4F2607326E009BF703 /* EditBasicInfo.swift */,
|
||||||
@@ -267,6 +277,7 @@
|
|||||||
E257101225B1B2790055B23B /* Models */ = {
|
E257101225B1B2790055B23B /* Models */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
E254F905260D0818009295A5 /* AbilityViewModel.swift */,
|
||||||
E216B7B6260C5A9800FB205F /* ChallengeRatingViewModel.swift */,
|
E216B7B6260C5A9800FB205F /* ChallengeRatingViewModel.swift */,
|
||||||
E20209E625D8DEB600EFE733 /* Enums */,
|
E20209E625D8DEB600EFE733 /* Enums */,
|
||||||
E216B790260C1FE800FB205F /* LanguageViewModel.swift */,
|
E216B790260C1FE800FB205F /* LanguageViewModel.swift */,
|
||||||
@@ -304,6 +315,9 @@
|
|||||||
dependencies = (
|
dependencies = (
|
||||||
);
|
);
|
||||||
name = MonsterCards;
|
name = MonsterCards;
|
||||||
|
packageProductDependencies = (
|
||||||
|
E254F900260D07C1009295A5 /* MarkdownUI */,
|
||||||
|
);
|
||||||
productName = MonsterCards;
|
productName = MonsterCards;
|
||||||
productReference = E2570FB525B1AC520055B23B /* MonsterCards.app */;
|
productReference = E2570FB525B1AC520055B23B /* MonsterCards.app */;
|
||||||
productType = "com.apple.product-type.application";
|
productType = "com.apple.product-type.application";
|
||||||
@@ -375,6 +389,9 @@
|
|||||||
Base,
|
Base,
|
||||||
);
|
);
|
||||||
mainGroup = E2570FAC25B1AC520055B23B;
|
mainGroup = E2570FAC25B1AC520055B23B;
|
||||||
|
packageReferences = (
|
||||||
|
E254F8FF260D07C1009295A5 /* XCRemoteSwiftPackageReference "MarkdownUI" */,
|
||||||
|
);
|
||||||
productRefGroup = E2570FB625B1AC520055B23B /* Products */;
|
productRefGroup = E2570FB625B1AC520055B23B /* Products */;
|
||||||
projectDirPath = "";
|
projectDirPath = "";
|
||||||
projectRoot = "";
|
projectRoot = "";
|
||||||
@@ -423,6 +440,7 @@
|
|||||||
E216B799260C2DF200FB205F /* EditLanguages.swift in Sources */,
|
E216B799260C2DF200FB205F /* EditLanguages.swift in Sources */,
|
||||||
E2570FBB25B1AC520055B23B /* ContentView.swift in Sources */,
|
E2570FBB25B1AC520055B23B /* ContentView.swift in Sources */,
|
||||||
E24ACE502607326E009BF703 /* EditBasicInfo.swift in Sources */,
|
E24ACE502607326E009BF703 /* EditBasicInfo.swift in Sources */,
|
||||||
|
E254F90E260D19A0009295A5 /* EditAbilities.swift in Sources */,
|
||||||
E2570FC525B1AC550055B23B /* MonsterCards.xcdatamodeld in Sources */,
|
E2570FC525B1AC550055B23B /* MonsterCards.xcdatamodeld in Sources */,
|
||||||
E2182E6425B22F8A00DFAEF8 /* Monster+CoreDataClass.swift in Sources */,
|
E2182E6425B22F8A00DFAEF8 /* Monster+CoreDataClass.swift in Sources */,
|
||||||
E216B791260C1FE800FB205F /* LanguageViewModel.swift in Sources */,
|
E216B791260C1FE800FB205F /* LanguageViewModel.swift in Sources */,
|
||||||
@@ -449,9 +467,11 @@
|
|||||||
E2CB0DE1260887ED00142591 /* StringViewModel.swift in Sources */,
|
E2CB0DE1260887ED00142591 /* StringViewModel.swift in Sources */,
|
||||||
E20209F425D8E04300EFE733 /* ProficiencyType.swift in Sources */,
|
E20209F425D8E04300EFE733 /* ProficiencyType.swift in Sources */,
|
||||||
E2CB0DC526086E5F00142591 /* SizeType.swift in Sources */,
|
E2CB0DC526086E5F00142591 /* SizeType.swift in Sources */,
|
||||||
|
E254F906260D0818009295A5 /* AbilityViewModel.swift in Sources */,
|
||||||
E2570FFA25B1AE020055B23B /* Collections.swift in Sources */,
|
E2570FFA25B1AE020055B23B /* Collections.swift in Sources */,
|
||||||
E24ACE5B2607F0F2009BF703 /* EditSpeed.swift in Sources */,
|
E24ACE5B2607F0F2009BF703 /* EditSpeed.swift in Sources */,
|
||||||
E2570FB925B1AC520055B23B /* MonsterCardsApp.swift in Sources */,
|
E2570FB925B1AC520055B23B /* MonsterCardsApp.swift in Sources */,
|
||||||
|
E254F913260D1F6D009295A5 /* EditAbility.swift in Sources */,
|
||||||
E216B7B7260C5A9800FB205F /* ChallengeRatingViewModel.swift in Sources */,
|
E216B7B7260C5A9800FB205F /* ChallengeRatingViewModel.swift in Sources */,
|
||||||
E20209D325D8DD9600EFE733 /* Skill+CoreDataClass.swift in Sources */,
|
E20209D325D8DD9600EFE733 /* Skill+CoreDataClass.swift in Sources */,
|
||||||
E24ACE652607F55D009BF703 /* EditSavingThrows.swift in Sources */,
|
E24ACE652607F55D009BF703 /* EditSavingThrows.swift in Sources */,
|
||||||
@@ -781,6 +801,25 @@
|
|||||||
};
|
};
|
||||||
/* End XCConfigurationList section */
|
/* 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 */
|
/* Begin XCVersionGroup section */
|
||||||
E2570FC325B1AC550055B23B /* MonsterCards.xcdatamodeld */ = {
|
E2570FC325B1AC550055B23B /* MonsterCards.xcdatamodeld */ = {
|
||||||
isa = XCVersionGroup;
|
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>
|
<dict>
|
||||||
<key>SchemeUserState</key>
|
<key>SchemeUserState</key>
|
||||||
<dict>
|
<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>
|
<key>MonsterCards.xcscheme_^#shared#^_</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>orderHint</key>
|
<key>orderHint</key>
|
||||||
|
|||||||
116
iOS/MonsterCards/Models/AbilityViewModel.swift
Normal file
116
iOS/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 challengeRating: ChallengeRating
|
||||||
@Published var customChallengeRating: String
|
@Published var customChallengeRating: String
|
||||||
@Published var customProficiencyBonus: Int64
|
@Published var customProficiencyBonus: Int64
|
||||||
|
@Published var abilities: [AbilityViewModel]
|
||||||
|
|
||||||
init(_ rawMonster: Monster? = nil) {
|
init(_ rawMonster: Monster? = nil) {
|
||||||
self.name = ""
|
self.name = ""
|
||||||
@@ -112,6 +113,7 @@ class MonsterViewModel: ObservableObject {
|
|||||||
self.challengeRating = .one
|
self.challengeRating = .one
|
||||||
self.customChallengeRating = ""
|
self.customChallengeRating = ""
|
||||||
self.customProficiencyBonus = 0
|
self.customProficiencyBonus = 0
|
||||||
|
self.abilities = []
|
||||||
|
|
||||||
if (rawMonster != nil) {
|
if (rawMonster != nil) {
|
||||||
self.copyFromMonster(monster: rawMonster!)
|
self.copyFromMonster(monster: rawMonster!)
|
||||||
@@ -186,7 +188,12 @@ class MonsterViewModel: ObservableObject {
|
|||||||
.sorted()
|
.sorted()
|
||||||
|
|
||||||
self.languages = (monster.languages ?? [])
|
self.languages = (monster.languages ?? [])
|
||||||
|
.map {LanguageViewModel($0.name, $0.speaks)}
|
||||||
.sorted()
|
.sorted()
|
||||||
|
|
||||||
|
// These are manually sorted in the UI
|
||||||
|
self.abilities = (monster.abilities ?? [])
|
||||||
|
.map {AbilityViewModel($0.name, $0.abilityDescription)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func copyToMonster(monster: Monster) {
|
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.
|
// 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.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"?>
|
<?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="">
|
<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">
|
<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="alignment" attributeType="String" defaultValueString=""/>
|
||||||
<attribute name="armorType" attributeType="String" defaultValueString=""/>
|
<attribute name="armorType" attributeType="String" defaultValueString=""/>
|
||||||
<attribute name="baseSpeed" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
|
<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"/>
|
<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="884"/>
|
<element name="Monster" positionX="-63" positionY="-18" width="128" height="899"/>
|
||||||
<element name="Skill" positionX="-63" positionY="135" width="128" height="14"/>
|
<element name="Skill" positionX="-63" positionY="135" width="128" height="14"/>
|
||||||
</elements>
|
</elements>
|
||||||
</model>
|
</model>
|
||||||
64
iOS/MonsterCards/Views/EditAbilities.swift
Normal file
64
iOS/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
iOS/MonsterCards/Views/EditAbility.swift
Normal file
29
iOS/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(
|
NavigationLink(
|
||||||
"Challenge Rating",
|
"Challenge Rating",
|
||||||
destination: EditChallengeRating(viewModel: monsterViewModel))
|
destination: EditChallengeRating(viewModel: monsterViewModel))
|
||||||
|
|
||||||
|
NavigationLink(
|
||||||
|
"Abilities", destination: EditAbilities(viewModel: monsterViewModel, path: \.abilities, title: "Abilities"))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ struct EditStrings: View {
|
|||||||
.toolbar(content: {
|
.toolbar(content: {
|
||||||
Button(
|
Button(
|
||||||
action: {
|
action: {
|
||||||
let newDamageType = StringViewModel()
|
let newString = StringViewModel()
|
||||||
viewModel[keyPath: path].append(newDamageType)
|
viewModel[keyPath: path].append(newString)
|
||||||
viewModel[keyPath: path] = viewModel[keyPath: path].sorted()
|
viewModel[keyPath: path] = viewModel[keyPath: path].sorted()
|
||||||
},
|
},
|
||||||
label: {
|
label: {
|
||||||
@@ -44,13 +44,17 @@ struct EditStrings: View {
|
|||||||
})
|
})
|
||||||
.onAppear(perform: {
|
.onAppear(perform: {
|
||||||
viewModel[keyPath: path] = viewModel[keyPath: path].sorted()
|
viewModel[keyPath: path] = viewModel[keyPath: path].sorted()
|
||||||
}).navigationTitle(title)
|
})
|
||||||
|
.navigationTitle(title)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct EditStrings_Previews: PreviewProvider {
|
struct EditStrings_Previews: PreviewProvider {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
let viewModel = MonsterViewModel()
|
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 SwiftUI
|
||||||
|
import MarkdownUI
|
||||||
|
|
||||||
struct LabeledField<Content: View>: View {
|
struct LabeledField<Content: View>: View {
|
||||||
@Environment(\.horizontalSizeClass) var sizeClass
|
@Environment(\.horizontalSizeClass) var sizeClass
|
||||||
@@ -209,6 +210,7 @@ struct MonsterDetail: View {
|
|||||||
VStack (alignment: .leading) {
|
VStack (alignment: .leading) {
|
||||||
let monsterLanguagesDescription = monster.languagesDescription
|
let monsterLanguagesDescription = monster.languagesDescription
|
||||||
let monsterChallengeRatingDescription = monster.challengeRatingDescription
|
let monsterChallengeRatingDescription = monster.challengeRatingDescription
|
||||||
|
let monsterAbilities: [AbilityViewModel] = monster.abilities ?? []
|
||||||
|
|
||||||
BasicInfoView(monster: monster)
|
BasicInfoView(monster: monster)
|
||||||
|
|
||||||
@@ -243,6 +245,14 @@ struct MonsterDetail: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Abilities
|
// Abilities
|
||||||
|
if (monsterAbilities.count > 0) {
|
||||||
|
ForEach(monsterAbilities) { ability in
|
||||||
|
VStack {
|
||||||
|
Markdown(Document(ability.renderedText(monster)/*.fullText*/))
|
||||||
|
Divider()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Actions
|
// Actions
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user