Reorganized the MonsterDetail view to get around the 10 items per group limit.
Adds layout for resistances, immunities, and languages.
This commit is contained in:
@@ -42,6 +42,10 @@
|
|||||||
E2BD703125B3BBB90058ED69 /* MCStepperField.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2BD703025B3BBB90058ED69 /* MCStepperField.swift */; };
|
E2BD703125B3BBB90058ED69 /* MCStepperField.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2BD703025B3BBB90058ED69 /* MCStepperField.swift */; };
|
||||||
E2CB0DB326080C0500142591 /* EditSkill.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2CB0DB226080C0500142591 /* EditSkill.swift */; };
|
E2CB0DB326080C0500142591 /* EditSkill.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2CB0DB226080C0500142591 /* EditSkill.swift */; };
|
||||||
E2CB0DB826081A2F00142591 /* MCAbilityScorePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2CB0DB726081A2F00142591 /* MCAbilityScorePicker.swift */; };
|
E2CB0DB826081A2F00142591 /* MCAbilityScorePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2CB0DB726081A2F00142591 /* MCAbilityScorePicker.swift */; };
|
||||||
|
E2CB0DC026086E3C00142591 /* ChallengeRating.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2CB0DBF26086E3C00142591 /* ChallengeRating.swift */; };
|
||||||
|
E2CB0DC526086E5F00142591 /* SizeType.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2CB0DC426086E5F00142591 /* SizeType.swift */; };
|
||||||
|
E2CB0DCA26086E8300142591 /* ArmorType.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2CB0DC926086E8300142591 /* ArmorType.swift */; };
|
||||||
|
E2CB0DD72608720000142591 /* StringHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2CB0DD62608720000142591 /* StringHelper.swift */; };
|
||||||
E2D473FD25B532C900CB36D7 /* Color+Hex.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2D473FC25B532C900CB36D7 /* Color+Hex.swift */; };
|
E2D473FD25B532C900CB36D7 /* Color+Hex.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2D473FC25B532C900CB36D7 /* Color+Hex.swift */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
@@ -104,6 +108,10 @@
|
|||||||
E2BD703025B3BBB90058ED69 /* MCStepperField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MCStepperField.swift; sourceTree = "<group>"; };
|
E2BD703025B3BBB90058ED69 /* MCStepperField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MCStepperField.swift; sourceTree = "<group>"; };
|
||||||
E2CB0DB226080C0500142591 /* EditSkill.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditSkill.swift; sourceTree = "<group>"; };
|
E2CB0DB226080C0500142591 /* EditSkill.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditSkill.swift; sourceTree = "<group>"; };
|
||||||
E2CB0DB726081A2F00142591 /* MCAbilityScorePicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MCAbilityScorePicker.swift; sourceTree = "<group>"; };
|
E2CB0DB726081A2F00142591 /* MCAbilityScorePicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MCAbilityScorePicker.swift; sourceTree = "<group>"; };
|
||||||
|
E2CB0DBF26086E3C00142591 /* ChallengeRating.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChallengeRating.swift; sourceTree = "<group>"; };
|
||||||
|
E2CB0DC426086E5F00142591 /* SizeType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SizeType.swift; sourceTree = "<group>"; };
|
||||||
|
E2CB0DC926086E8300142591 /* ArmorType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArmorType.swift; sourceTree = "<group>"; };
|
||||||
|
E2CB0DD62608720000142591 /* StringHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringHelper.swift; sourceTree = "<group>"; };
|
||||||
E2D473FC25B532C900CB36D7 /* Color+Hex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Color+Hex.swift"; sourceTree = "<group>"; };
|
E2D473FC25B532C900CB36D7 /* Color+Hex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Color+Hex.swift"; sourceTree = "<group>"; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
@@ -137,7 +145,10 @@
|
|||||||
children = (
|
children = (
|
||||||
E20209E725D8DEC100EFE733 /* AbilityScore.swift */,
|
E20209E725D8DEC100EFE733 /* AbilityScore.swift */,
|
||||||
E20209F325D8E04300EFE733 /* AdvantageType.swift */,
|
E20209F325D8E04300EFE733 /* AdvantageType.swift */,
|
||||||
|
E2CB0DC926086E8300142591 /* ArmorType.swift */,
|
||||||
|
E2CB0DBF26086E3C00142591 /* ChallengeRating.swift */,
|
||||||
E20209F225D8E04300EFE733 /* ProficiencyType.swift */,
|
E20209F225D8E04300EFE733 /* ProficiencyType.swift */,
|
||||||
|
E2CB0DC426086E5F00142591 /* SizeType.swift */,
|
||||||
);
|
);
|
||||||
path = Enums;
|
path = Enums;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -248,6 +259,7 @@
|
|||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
E2D473FC25B532C900CB36D7 /* Color+Hex.swift */,
|
E2D473FC25B532C900CB36D7 /* Color+Hex.swift */,
|
||||||
|
E2CB0DD62608720000142591 /* StringHelper.swift */,
|
||||||
);
|
);
|
||||||
path = Helpers;
|
path = Helpers;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -393,8 +405,10 @@
|
|||||||
E257100925B1B2480055B23B /* MonsterDetail.swift in Sources */,
|
E257100925B1B2480055B23B /* MonsterDetail.swift in Sources */,
|
||||||
E2D473FD25B532C900CB36D7 /* Color+Hex.swift in Sources */,
|
E2D473FD25B532C900CB36D7 /* Color+Hex.swift in Sources */,
|
||||||
E2B5285925B3028700AAA69E /* EditMonster.swift in Sources */,
|
E2B5285925B3028700AAA69E /* EditMonster.swift in Sources */,
|
||||||
|
E2CB0DD72608720000142591 /* StringHelper.swift in Sources */,
|
||||||
E2570FF525B1ADEB0055B23B /* Dashboard.swift in Sources */,
|
E2570FF525B1ADEB0055B23B /* Dashboard.swift in Sources */,
|
||||||
E2CB0DB826081A2F00142591 /* MCAbilityScorePicker.swift in Sources */,
|
E2CB0DB826081A2F00142591 /* MCAbilityScorePicker.swift in Sources */,
|
||||||
|
E2CB0DC026086E3C00142591 /* ChallengeRating.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 */,
|
E24ACE6A2607F715009BF703 /* EditSkills.swift in Sources */,
|
||||||
@@ -402,8 +416,10 @@
|
|||||||
E2570FFF25B1AE180055B23B /* Library.swift in Sources */,
|
E2570FFF25B1AE180055B23B /* Library.swift in Sources */,
|
||||||
E2BD703125B3BBB90058ED69 /* MCStepperField.swift in Sources */,
|
E2BD703125B3BBB90058ED69 /* MCStepperField.swift in Sources */,
|
||||||
E2CB0DB326080C0500142591 /* EditSkill.swift in Sources */,
|
E2CB0DB326080C0500142591 /* EditSkill.swift in Sources */,
|
||||||
|
E2CB0DCA26086E8300142591 /* ArmorType.swift in Sources */,
|
||||||
E24ACE562607EE94009BF703 /* EditArmor.swift in Sources */,
|
E24ACE562607EE94009BF703 /* EditArmor.swift in Sources */,
|
||||||
E20209F425D8E04300EFE733 /* ProficiencyType.swift in Sources */,
|
E20209F425D8E04300EFE733 /* ProficiencyType.swift in Sources */,
|
||||||
|
E2CB0DC526086E5F00142591 /* SizeType.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 */,
|
||||||
|
|||||||
40
MonsterCards/Helpers/StringHelper.swift
Normal file
40
MonsterCards/Helpers/StringHelper.swift
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
//
|
||||||
|
// StringHelper.swift
|
||||||
|
// MonsterCards
|
||||||
|
//
|
||||||
|
// Created by Tom Hicks on 3/21/21.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
class StringHelper {
|
||||||
|
static func oxfordJoin(
|
||||||
|
_ strings: [String],
|
||||||
|
_ separator: String,
|
||||||
|
_ lastSeparator: String,
|
||||||
|
_ onlySeparator: String
|
||||||
|
) -> String {
|
||||||
|
let numStrings = strings.count
|
||||||
|
if (numStrings < 1) {
|
||||||
|
return "";
|
||||||
|
} else if (numStrings == 2) {
|
||||||
|
return strings[0] + onlySeparator + strings[1]
|
||||||
|
} else {
|
||||||
|
var joined = ""
|
||||||
|
var index = 0
|
||||||
|
let lastIndex = numStrings - 1
|
||||||
|
|
||||||
|
strings.forEach {
|
||||||
|
if index > 0 && index < lastIndex {
|
||||||
|
joined.append(separator)
|
||||||
|
} else if (index > 0 && index >= lastIndex) {
|
||||||
|
joined.append(lastSeparator)
|
||||||
|
}
|
||||||
|
joined.append($0)
|
||||||
|
index = index + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
return joined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
50
MonsterCards/Models/Enums/ArmorType.swift
Normal file
50
MonsterCards/Models/Enums/ArmorType.swift
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
//
|
||||||
|
// ArmorType.swift
|
||||||
|
// MonsterCards
|
||||||
|
//
|
||||||
|
// Created by Tom Hicks on 3/21/21.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
enum ArmorType: String, CaseIterable, Identifiable {
|
||||||
|
case none = "none"
|
||||||
|
case naturalArmor = "natural armor"
|
||||||
|
case mageArmor = "mage armor"
|
||||||
|
case padded = "padded"
|
||||||
|
case leather = "leather"
|
||||||
|
case studdedLeather = "studded"
|
||||||
|
case hide = "hide"
|
||||||
|
case chainShirt = "chain shirt"
|
||||||
|
case scaleMail = "scale mail"
|
||||||
|
case breastplate = "breastplate"
|
||||||
|
case halfPlate = "half plate"
|
||||||
|
case ringMail = "ring mail"
|
||||||
|
case chainMail = "chain mail"
|
||||||
|
case splintMail = "splint"
|
||||||
|
case plateMail = "plate"
|
||||||
|
case other = "other"
|
||||||
|
|
||||||
|
var id: ArmorType { self }
|
||||||
|
|
||||||
|
var displayName: String {
|
||||||
|
switch self {
|
||||||
|
case .none: return "None"
|
||||||
|
case .naturalArmor: return "Natural Armor"
|
||||||
|
case .mageArmor: return "Mage Armor"
|
||||||
|
case .padded: return "Padded"
|
||||||
|
case .leather: return "Leather"
|
||||||
|
case .studdedLeather: return "Studded Leather"
|
||||||
|
case .hide: return "Hide"
|
||||||
|
case .chainShirt: return "Chain Shirt"
|
||||||
|
case .scaleMail: return "Scale Mail"
|
||||||
|
case .breastplate: return "Breastplate"
|
||||||
|
case .halfPlate: return "Half Plate"
|
||||||
|
case .ringMail: return "Ring Mail"
|
||||||
|
case .chainMail: return "Chain Mail"
|
||||||
|
case .splintMail: return "Splint Mail"
|
||||||
|
case .plateMail: return "Plate Mail"
|
||||||
|
case .other: return "Other"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
53
MonsterCards/Models/Enums/ChallengeRating.swift
Normal file
53
MonsterCards/Models/Enums/ChallengeRating.swift
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
//
|
||||||
|
// ChallengeRating.swift
|
||||||
|
// MonsterCards
|
||||||
|
//
|
||||||
|
// Created by Tom Hicks on 3/21/21.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
enum ChallengeRating: String, CaseIterable, Identifiable {
|
||||||
|
case zero = "0"
|
||||||
|
case oneEighth = "1/8"
|
||||||
|
case oneQuarter = "1/4"
|
||||||
|
case oneHalf = "1/2"
|
||||||
|
case one = "1"
|
||||||
|
case two = "2"
|
||||||
|
case three = "3"
|
||||||
|
case four = "4"
|
||||||
|
case five = "5"
|
||||||
|
case six = "6"
|
||||||
|
case seven = "7"
|
||||||
|
case eight = "8"
|
||||||
|
case nine = "9"
|
||||||
|
case ten = "10"
|
||||||
|
case eleven = "11"
|
||||||
|
case twelve = "12"
|
||||||
|
case thirteen = "13"
|
||||||
|
case fourteen = "14"
|
||||||
|
case fifteen = "15"
|
||||||
|
case sixteen = "16"
|
||||||
|
case seventeen = "17"
|
||||||
|
case eighteen = "18"
|
||||||
|
case nineteen = "19"
|
||||||
|
case twenty = "20"
|
||||||
|
case twentyOne = "21"
|
||||||
|
case twentyTwo = "22"
|
||||||
|
case twentyThree = "23"
|
||||||
|
case twentyFour = "24"
|
||||||
|
case twentyFive = "25"
|
||||||
|
case twentySix = "26"
|
||||||
|
case twentySeven = "27"
|
||||||
|
case twentyEight = "28"
|
||||||
|
case twentyNine = "29"
|
||||||
|
case thirty = "30"
|
||||||
|
case custom = "*"
|
||||||
|
|
||||||
|
var id: ChallengeRating { self }
|
||||||
|
|
||||||
|
// Probably don't need this
|
||||||
|
var displayName: String {
|
||||||
|
return rawValue
|
||||||
|
}
|
||||||
|
}
|
||||||
30
MonsterCards/Models/Enums/SizeType.swift
Normal file
30
MonsterCards/Models/Enums/SizeType.swift
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
//
|
||||||
|
// SizeType.swift
|
||||||
|
// MonsterCards
|
||||||
|
//
|
||||||
|
// Created by Tom Hicks on 3/21/21.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
enum SizeType: String, CaseIterable, Identifiable {
|
||||||
|
case tiny = "tiny"
|
||||||
|
case small = "small"
|
||||||
|
case medium = "medium"
|
||||||
|
case large = "large"
|
||||||
|
case huge = "huge"
|
||||||
|
case gargantuan = "gargantuan"
|
||||||
|
|
||||||
|
var id: SizeType { self }
|
||||||
|
|
||||||
|
var displayName: String {
|
||||||
|
switch self {
|
||||||
|
case .tiny: return "Tiny"
|
||||||
|
case .small: return "Small"
|
||||||
|
case .medium: return "Medium"
|
||||||
|
case .large: return "Large"
|
||||||
|
case .huge: return "Huge"
|
||||||
|
case .gargantuan: return "gargantuan"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -625,115 +625,84 @@ public class Monster: NSManagedObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: OTHER
|
||||||
|
|
||||||
|
var damageVulnerabilitiesArray: [String] {
|
||||||
|
get {
|
||||||
|
return ["Fire", "Poison", "Psychic"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var damageVulnerabilitiesDescription: String {
|
||||||
|
get {
|
||||||
|
let sortedVulnerabilities = self.damageVulnerabilitiesArray.sorted()
|
||||||
|
|
||||||
|
return StringHelper.oxfordJoin(sortedVulnerabilities, ", ", ", and ", " and ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var damageResistancesArray: [String] {
|
||||||
|
get {
|
||||||
|
return ["Ice", "Electric"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var damageResistancesDescription: String {
|
||||||
|
get {
|
||||||
|
let sortedResistances = self.damageResistancesArray.sorted()
|
||||||
|
return StringHelper.oxfordJoin(sortedResistances, ", ", ", and ", " and ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var damageImmunitiesArray: [String] {
|
||||||
|
get {
|
||||||
|
return ["Slashing"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var damageImmunitiesDescription: String {
|
||||||
|
get {
|
||||||
|
let sortedImmunities = self.damageImmunitiesArray.sorted()
|
||||||
|
return StringHelper.oxfordJoin(sortedImmunities, ", ", ", and ", " and ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var conditionImmunitiesArray: [String] {
|
||||||
|
get {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var conditionImmunitiesDescription: String {
|
||||||
|
get {
|
||||||
|
let sortedImmunities = self.conditionImmunitiesArray.sorted()
|
||||||
|
return StringHelper.oxfordJoin(sortedImmunities, ", ", ", and ", " and ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var languagesArray: [String] {
|
||||||
|
get {
|
||||||
|
return ["Common", "Goblin"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var languagesDescription: String {
|
||||||
|
get {
|
||||||
|
let sortedLanguages = self.languagesArray.sorted()
|
||||||
|
return StringHelper.oxfordJoin(sortedLanguages, ", ", ", and ", " and ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var challengeRatingDescription: String {
|
||||||
|
get {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: End
|
// MARK: End
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ArmorType: String, CaseIterable, Identifiable {
|
|
||||||
case none = "none"
|
|
||||||
case naturalArmor = "natural armor"
|
|
||||||
case mageArmor = "mage armor"
|
|
||||||
case padded = "padded"
|
|
||||||
case leather = "leather"
|
|
||||||
case studdedLeather = "studded"
|
|
||||||
case hide = "hide"
|
|
||||||
case chainShirt = "chain shirt"
|
|
||||||
case scaleMail = "scale mail"
|
|
||||||
case breastplate = "breastplate"
|
|
||||||
case halfPlate = "half plate"
|
|
||||||
case ringMail = "ring mail"
|
|
||||||
case chainMail = "chain mail"
|
|
||||||
case splintMail = "splint"
|
|
||||||
case plateMail = "plate"
|
|
||||||
case other = "other"
|
|
||||||
|
|
||||||
var id: ArmorType { self }
|
|
||||||
|
|
||||||
var displayName: String {
|
|
||||||
switch self {
|
|
||||||
case .none: return "None"
|
|
||||||
case .naturalArmor: return "Natural Armor"
|
|
||||||
case .mageArmor: return "Mage Armor"
|
|
||||||
case .padded: return "Padded"
|
|
||||||
case .leather: return "Leather"
|
|
||||||
case .studdedLeather: return "Studded Leather"
|
|
||||||
case .hide: return "Hide"
|
|
||||||
case .chainShirt: return "Chain Shirt"
|
|
||||||
case .scaleMail: return "Scale Mail"
|
|
||||||
case .breastplate: return "Breastplate"
|
|
||||||
case .halfPlate: return "Half Plate"
|
|
||||||
case .ringMail: return "Ring Mail"
|
|
||||||
case .chainMail: return "Chain Mail"
|
|
||||||
case .splintMail: return "Splint Mail"
|
|
||||||
case .plateMail: return "Plate Mail"
|
|
||||||
case .other: return "Other"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum SizeType: String, CaseIterable, Identifiable {
|
|
||||||
case tiny = "tiny"
|
|
||||||
case small = "small"
|
|
||||||
case medium = "medium"
|
|
||||||
case large = "large"
|
|
||||||
case huge = "huge"
|
|
||||||
case gargantuan = "gargantuan"
|
|
||||||
|
|
||||||
var id: SizeType { self }
|
|
||||||
|
|
||||||
var displayName: String {
|
|
||||||
switch self {
|
|
||||||
case .tiny: return "Tiny"
|
|
||||||
case .small: return "Small"
|
|
||||||
case .medium: return "Medium"
|
|
||||||
case .large: return "Large"
|
|
||||||
case .huge: return "Huge"
|
|
||||||
case .gargantuan: return "gargantuan"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum ChallengeRating: String, CaseIterable, Identifiable {
|
|
||||||
case zero = "0"
|
|
||||||
case oneEighth = "1/8"
|
|
||||||
case oneQuarter = "1/4"
|
|
||||||
case oneHalf = "1/2"
|
|
||||||
case one = "1"
|
|
||||||
case two = "2"
|
|
||||||
case three = "3"
|
|
||||||
case four = "4"
|
|
||||||
case five = "5"
|
|
||||||
case six = "6"
|
|
||||||
case seven = "7"
|
|
||||||
case eight = "8"
|
|
||||||
case nine = "9"
|
|
||||||
case ten = "10"
|
|
||||||
case eleven = "11"
|
|
||||||
case twelve = "12"
|
|
||||||
case thirteen = "13"
|
|
||||||
case fourteen = "14"
|
|
||||||
case fifteen = "15"
|
|
||||||
case sixteen = "16"
|
|
||||||
case seventeen = "17"
|
|
||||||
case eighteen = "18"
|
|
||||||
case nineteen = "19"
|
|
||||||
case twenty = "20"
|
|
||||||
case twentyOne = "21"
|
|
||||||
case twentyTwo = "22"
|
|
||||||
case twentyThree = "23"
|
|
||||||
case twentyFour = "24"
|
|
||||||
case twentyFive = "25"
|
|
||||||
case twentySix = "26"
|
|
||||||
case twentySeven = "27"
|
|
||||||
case twentyEight = "28"
|
|
||||||
case twentyNine = "29"
|
|
||||||
case thirty = "30"
|
|
||||||
case custom = "*"
|
|
||||||
|
|
||||||
var id: ChallengeRating { self }
|
|
||||||
|
|
||||||
// Probably don't need this
|
|
||||||
var displayName: String {
|
|
||||||
return rawValue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -70,6 +70,127 @@ struct SmallAbilityScore: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct BasicInfoView: View {
|
||||||
|
@ObservedObject var monster: Monster
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
let monsterMeta = monster.meta
|
||||||
|
let monsterArmorClassDescription = monster.armorClassDescription
|
||||||
|
let monsterHitPoints = monster.hitPoints
|
||||||
|
let monsterSpeed = monster.speed
|
||||||
|
|
||||||
|
// meta: "(large humanoid (elf) lawful evil"
|
||||||
|
if (!monsterMeta.isEmpty) {
|
||||||
|
Text(monsterMeta)
|
||||||
|
.font(.subheadline)
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
}
|
||||||
|
|
||||||
|
SectionDivider()
|
||||||
|
|
||||||
|
// AC
|
||||||
|
if (!monsterArmorClassDescription.isEmpty) {
|
||||||
|
LabeledField("Armor Class") {
|
||||||
|
Text(monsterArmorClassDescription)// armor class
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// HP
|
||||||
|
if (!monsterHitPoints.isEmpty) {
|
||||||
|
LabeledField("Hit Points") {
|
||||||
|
Text(monsterHitPoints) // hit points
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Speed
|
||||||
|
if (!monsterSpeed.isEmpty) {
|
||||||
|
LabeledField("Speed") {
|
||||||
|
Text(monsterSpeed) // speed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct AbilityScoresView: View {
|
||||||
|
@ObservedObject var monster: Monster
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
SectionDivider()
|
||||||
|
|
||||||
|
// Ability Scores
|
||||||
|
HStack {
|
||||||
|
SmallAbilityScore("STR", monster.strengthScore, monster.strengthModifier)
|
||||||
|
SmallAbilityScore("DEX", monster.dexterityScore, monster.dexterityModifier)
|
||||||
|
SmallAbilityScore("CON", monster.constitutionScore, monster.constitutionModifier)
|
||||||
|
SmallAbilityScore("INT", monster.intelligenceScore, monster.intelligenceModifier)
|
||||||
|
SmallAbilityScore("WIS", monster.wisdomScore, monster.wisdomModifier)
|
||||||
|
SmallAbilityScore("CHA", monster.charismaScore, monster.charismaModifier)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ResistancesAndImmunitiesView: View {
|
||||||
|
@ObservedObject var monster: Monster
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
let monsterDamageVulnerabilitiesDescription = monster.damageVulnerabilitiesDescription
|
||||||
|
let monsterDamageResistancesDescription = monster.damageResistancesDescription
|
||||||
|
let monsterDamageImmunitiesDescription = monster.damageImmunitiesDescription
|
||||||
|
let monsterConditionImmunitiesDescription = monster.conditionImmunitiesDescription
|
||||||
|
|
||||||
|
// Damage Vulnerabilities
|
||||||
|
if (!monsterDamageVulnerabilitiesDescription.isEmpty) {
|
||||||
|
LabeledField("Damage Vulnerabilities") {
|
||||||
|
Text(monsterDamageVulnerabilitiesDescription)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Damage Resistances
|
||||||
|
if (!monsterDamageResistancesDescription.isEmpty) {
|
||||||
|
LabeledField("Damage Resistances") {
|
||||||
|
Text(monsterDamageResistancesDescription)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Damage Immunities
|
||||||
|
if (!monsterDamageImmunitiesDescription.isEmpty) {
|
||||||
|
LabeledField("Damage Immunities") {
|
||||||
|
Text(monsterDamageImmunitiesDescription)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Condition Immunities
|
||||||
|
if (!monsterConditionImmunitiesDescription.isEmpty) {
|
||||||
|
LabeledField("Condition Immunities") {
|
||||||
|
Text(monsterConditionImmunitiesDescription)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SavingThrowsAndSkillsView: View {
|
||||||
|
@ObservedObject var monster: Monster
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
let savingThrowsDescription = monster.savingThrowsDescription
|
||||||
|
let skillsDescription = monster.skillsDescription
|
||||||
|
|
||||||
|
// Saving Throws
|
||||||
|
if (!savingThrowsDescription.isEmpty) {
|
||||||
|
LabeledField("Saving Throws") {
|
||||||
|
Text(savingThrowsDescription)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skills
|
||||||
|
if (!skillsDescription.isEmpty) {
|
||||||
|
LabeledField("Skills") {
|
||||||
|
Text(skillsDescription)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct MonsterDetail: View {
|
struct MonsterDetail: View {
|
||||||
let kTextColor: Color = Color(hex: 0x982818)
|
let kTextColor: Color = Color(hex: 0x982818)
|
||||||
|
|
||||||
@@ -78,72 +199,45 @@ struct MonsterDetail: View {
|
|||||||
var body: some View {
|
var body: some View {
|
||||||
ScrollView {
|
ScrollView {
|
||||||
VStack (alignment: .leading) {
|
VStack (alignment: .leading) {
|
||||||
let monsterMeta = monster.meta
|
let monsterLanguagesDescription = monster.languagesDescription
|
||||||
let monsterArmorClassDescription = monster.armorClassDescription
|
let monsterChallengeRatingDescription = monster.challengeRatingDescription
|
||||||
let monsterHitPoints = monster.hitPoints
|
|
||||||
let monsterSpeed = monster.speed
|
|
||||||
|
|
||||||
if (!monsterMeta.isEmpty) {
|
BasicInfoView(monster: monster)
|
||||||
// meta: "(large humanoid (elf) lawful evil"
|
|
||||||
Text(monsterMeta)
|
|
||||||
.font(.subheadline)
|
|
||||||
.foregroundColor(.secondary)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Find a way to hide unnecessarry dividiers.
|
// TODO: Find a way to hide unnecessarry dividiers.
|
||||||
// if sections 0, 1, 2, and 3 are present there should be a divider between each of them
|
// if sections 0, 1, 2, and 3 are present there should be a divider between each of them
|
||||||
// if section 1 is not present there should be one and only one divider between sections 0 and 2 as well as the one between 2 and 3
|
// if section 1 is not present there should be one and only one divider between sections 0 and 2 as well as the one between 2 and 3
|
||||||
// if sections 1 and 2 are not present there should be a single divider between sections 0 and 3
|
// if sections 1 and 2 are not present there should be a single divider between sections 0 and 3
|
||||||
SectionDivider()
|
|
||||||
|
|
||||||
if (!monsterArmorClassDescription.isEmpty) {
|
AbilityScoresView(monster: monster)
|
||||||
// AC
|
|
||||||
LabeledField("Armor Class") {
|
|
||||||
Text(monsterArmorClassDescription)// armor class
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!monsterHitPoints.isEmpty) {
|
|
||||||
// HP
|
|
||||||
LabeledField("Hit Points") {
|
|
||||||
Text(monsterHitPoints) // hit points
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Speed
|
|
||||||
if (!monsterSpeed.isEmpty) {
|
|
||||||
LabeledField("Speed") {
|
|
||||||
Text(monsterSpeed) // speed
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SectionDivider()
|
SectionDivider()
|
||||||
|
|
||||||
// Ability Scores
|
SavingThrowsAndSkillsView(monster: monster)
|
||||||
HStack {
|
|
||||||
SmallAbilityScore("STR", monster.strengthScore, monster.strengthModifier)
|
|
||||||
SmallAbilityScore("DEX", monster.dexterityScore, monster.dexterityModifier)
|
|
||||||
SmallAbilityScore("CON", monster.constitutionScore, monster.constitutionModifier)
|
|
||||||
SmallAbilityScore("INT", monster.intelligenceScore, monster.intelligenceModifier)
|
|
||||||
SmallAbilityScore("WIS", monster.wisdomScore, monster.wisdomModifier)
|
|
||||||
SmallAbilityScore("CHA", monster.charismaScore, monster.charismaModifier)
|
|
||||||
}
|
|
||||||
|
|
||||||
SectionDivider()
|
|
||||||
|
|
||||||
let savingThrowsDescription = monster.savingThrowsDescription
|
ResistancesAndImmunitiesView(monster: monster)
|
||||||
if (!savingThrowsDescription.isEmpty) {
|
|
||||||
LabeledField("Saving Throws") {
|
// Languages
|
||||||
Text(savingThrowsDescription)
|
if (!monsterLanguagesDescription.isEmpty) {
|
||||||
|
LabeledField("Languages") {
|
||||||
|
Text(monsterLanguagesDescription)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let skillsDescription = monster.skillsDescription
|
// Challenge Rating
|
||||||
if (!skillsDescription.isEmpty) {
|
if (!monsterChallengeRatingDescription.isEmpty) {
|
||||||
LabeledField("Skills") {
|
LabeledField("Challenge Rating") {
|
||||||
Text(skillsDescription)
|
Text(monsterChallengeRatingDescription)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Abilities
|
||||||
|
|
||||||
|
// Actions
|
||||||
|
|
||||||
|
// Legendary Actions
|
||||||
|
|
||||||
}
|
}
|
||||||
.padding(.horizontal)
|
.padding(.horizontal)
|
||||||
.foregroundColor(kTextColor)
|
.foregroundColor(kTextColor)
|
||||||
|
|||||||
Reference in New Issue
Block a user