Adds languages to the editor.
This commit is contained in:
@@ -15,6 +15,9 @@
|
||||
E20209FC25D8E19100EFE733 /* MonsterViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E20209FA25D8E19100EFE733 /* MonsterViewModel.swift */; };
|
||||
E210B83A25B42D980083EAC5 /* MCProficiencyPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = E210B83925B42D980083EAC5 /* MCProficiencyPicker.swift */; };
|
||||
E210B83F25B42DAB0083EAC5 /* MCAdvantagePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = E210B83E25B42DAB0083EAC5 /* MCAdvantagePicker.swift */; };
|
||||
E216B791260C1FE800FB205F /* LanguageViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E216B790260C1FE800FB205F /* LanguageViewModel.swift */; };
|
||||
E216B799260C2DF200FB205F /* EditLanguages.swift in Sources */ = {isa = PBXBuildFile; fileRef = E216B798260C2DF200FB205F /* EditLanguages.swift */; };
|
||||
E216B79E260C396F00FB205F /* EditLanguage.swift in Sources */ = {isa = PBXBuildFile; fileRef = E216B79D260C396F00FB205F /* EditLanguage.swift */; };
|
||||
E2182E6425B22F8A00DFAEF8 /* Monster+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2182E6225B22F8A00DFAEF8 /* Monster+CoreDataClass.swift */; };
|
||||
E24ACE502607326E009BF703 /* EditBasicInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = E24ACE4F2607326E009BF703 /* EditBasicInfo.swift */; };
|
||||
E24ACE562607EE94009BF703 /* EditArmor.swift in Sources */ = {isa = PBXBuildFile; fileRef = E24ACE552607EE94009BF703 /* EditArmor.swift */; };
|
||||
@@ -77,6 +80,9 @@
|
||||
E20209FA25D8E19100EFE733 /* MonsterViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MonsterViewModel.swift; sourceTree = "<group>"; };
|
||||
E210B83925B42D980083EAC5 /* MCProficiencyPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MCProficiencyPicker.swift; sourceTree = "<group>"; };
|
||||
E210B83E25B42DAB0083EAC5 /* MCAdvantagePicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MCAdvantagePicker.swift; sourceTree = "<group>"; };
|
||||
E216B790260C1FE800FB205F /* LanguageViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LanguageViewModel.swift; sourceTree = "<group>"; };
|
||||
E216B798260C2DF200FB205F /* EditLanguages.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditLanguages.swift; sourceTree = "<group>"; };
|
||||
E216B79D260C396F00FB205F /* EditLanguage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditLanguage.swift; sourceTree = "<group>"; };
|
||||
E2182E6225B22F8A00DFAEF8 /* Monster+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Monster+CoreDataClass.swift"; sourceTree = "<group>"; };
|
||||
E24ACE4F2607326E009BF703 /* EditBasicInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditBasicInfo.swift; sourceTree = "<group>"; };
|
||||
E24ACE552607EE94009BF703 /* EditArmor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditArmor.swift; sourceTree = "<group>"; };
|
||||
@@ -180,15 +186,15 @@
|
||||
E2570FB725B1AC520055B23B /* MonsterCards */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E2570FB825B1AC520055B23B /* MonsterCardsApp.swift */,
|
||||
E2D473FB25B5328800CB36D7 /* Helpers */,
|
||||
E257101225B1B2790055B23B /* Models */,
|
||||
E2570FEB25B1ADA90055B23B /* Views */,
|
||||
E2570FBC25B1AC550055B23B /* Assets.xcassets */,
|
||||
E2570FC125B1AC550055B23B /* Persistence.swift */,
|
||||
E2D473FB25B5328800CB36D7 /* Helpers */,
|
||||
E2570FC625B1AC550055B23B /* Info.plist */,
|
||||
E257101225B1B2790055B23B /* Models */,
|
||||
E2570FC325B1AC550055B23B /* MonsterCards.xcdatamodeld */,
|
||||
E2570FB825B1AC520055B23B /* MonsterCardsApp.swift */,
|
||||
E2570FC125B1AC550055B23B /* Persistence.swift */,
|
||||
E2570FBE25B1AC550055B23B /* Preview Content */,
|
||||
E2570FEB25B1ADA90055B23B /* Views */,
|
||||
);
|
||||
path = MonsterCards;
|
||||
sourceTree = "<group>";
|
||||
@@ -228,12 +234,14 @@
|
||||
E24ACE5F2607F45E009BF703 /* EditAbilityScores.swift */,
|
||||
E24ACE552607EE94009BF703 /* EditArmor.swift */,
|
||||
E24ACE4F2607326E009BF703 /* EditBasicInfo.swift */,
|
||||
E2CB0DE526088CE400142591 /* EditStrings.swift */,
|
||||
E216B79D260C396F00FB205F /* EditLanguage.swift */,
|
||||
E216B798260C2DF200FB205F /* EditLanguages.swift */,
|
||||
E2B5285825B3028700AAA69E /* EditMonster.swift */,
|
||||
E24ACE642607F55D009BF703 /* EditSavingThrows.swift */,
|
||||
E2CB0DB226080C0500142591 /* EditSkill.swift */,
|
||||
E24ACE692607F715009BF703 /* EditSkills.swift */,
|
||||
E24ACE5A2607F0F2009BF703 /* EditSpeed.swift */,
|
||||
E2CB0DE526088CE400142591 /* EditStrings.swift */,
|
||||
E2570FFE25B1AE180055B23B /* Library.swift */,
|
||||
E2CB0DB726081A2F00142591 /* MCAbilityScorePicker.swift */,
|
||||
E210B83E25B42DAB0083EAC5 /* MCAdvantagePicker.swift */,
|
||||
@@ -251,12 +259,13 @@
|
||||
E257101225B1B2790055B23B /* Models */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E2CB0DE0260887ED00142591 /* StringViewModel.swift */,
|
||||
E20209E625D8DEB600EFE733 /* Enums */,
|
||||
E216B790260C1FE800FB205F /* LanguageViewModel.swift */,
|
||||
E2182E6225B22F8A00DFAEF8 /* Monster+CoreDataClass.swift */,
|
||||
E20209FA25D8E19100EFE733 /* MonsterViewModel.swift */,
|
||||
E20209D225D8DD9600EFE733 /* Skill+CoreDataClass.swift */,
|
||||
E20209F925D8E19100EFE733 /* SkillViewModel.swift */,
|
||||
E2CB0DE0260887ED00142591 /* StringViewModel.swift */,
|
||||
);
|
||||
path = Models;
|
||||
sourceTree = "<group>";
|
||||
@@ -402,10 +411,12 @@
|
||||
E20209FB25D8E19100EFE733 /* SkillViewModel.swift in Sources */,
|
||||
E24ACE602607F45E009BF703 /* EditAbilityScores.swift in Sources */,
|
||||
E2570FC225B1AC550055B23B /* Persistence.swift in Sources */,
|
||||
E216B799260C2DF200FB205F /* EditLanguages.swift in Sources */,
|
||||
E2570FBB25B1AC520055B23B /* ContentView.swift in Sources */,
|
||||
E24ACE502607326E009BF703 /* EditBasicInfo.swift in Sources */,
|
||||
E2570FC525B1AC550055B23B /* MonsterCards.xcdatamodeld in Sources */,
|
||||
E2182E6425B22F8A00DFAEF8 /* Monster+CoreDataClass.swift in Sources */,
|
||||
E216B791260C1FE800FB205F /* LanguageViewModel.swift in Sources */,
|
||||
E210B83A25B42D980083EAC5 /* MCProficiencyPicker.swift in Sources */,
|
||||
E2570FF025B1ADC10055B23B /* Search.swift in Sources */,
|
||||
E257100925B1B2480055B23B /* MonsterDetail.swift in Sources */,
|
||||
@@ -420,6 +431,7 @@
|
||||
E24ACE6A2607F715009BF703 /* EditSkills.swift in Sources */,
|
||||
E20209FC25D8E19100EFE733 /* MonsterViewModel.swift in Sources */,
|
||||
E2570FFF25B1AE180055B23B /* Library.swift in Sources */,
|
||||
E216B79E260C396F00FB205F /* EditLanguage.swift in Sources */,
|
||||
E2BD703125B3BBB90058ED69 /* MCStepperField.swift in Sources */,
|
||||
E2CB0DE626088CE400142591 /* EditStrings.swift in Sources */,
|
||||
E2CB0DB326080C0500142591 /* EditSkill.swift in Sources */,
|
||||
|
||||
79
iOS/MonsterCards/Models/LanguageViewModel.swift
Normal file
79
iOS/MonsterCards/Models/LanguageViewModel.swift
Normal file
@@ -0,0 +1,79 @@
|
||||
//
|
||||
// LanguageViewModel.swift
|
||||
// MonsterCards
|
||||
//
|
||||
// Created by Tom Hicks on 3/24/21.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
// TODO: split this into separate Model and ViewModel classes later.
|
||||
public class LanguageViewModel : NSObject, ObservableObject, Comparable, Identifiable, NSSecureCoding {
|
||||
public static var supportsSecureCoding = true
|
||||
|
||||
public func encode(with coder: NSCoder) {
|
||||
coder.encode(self.name, forKey: "name")
|
||||
coder.encode(self.speaks, forKey: "speaks")
|
||||
}
|
||||
|
||||
public required init?(coder: NSCoder) {
|
||||
self.name = coder.decodeObject(of: NSString.self, forKey: "name")! as String
|
||||
self.speaks = coder.decodeBool(forKey: "speaks")
|
||||
}
|
||||
|
||||
public static func < (lhs: LanguageViewModel, rhs: LanguageViewModel) -> Bool {
|
||||
lhs.name < rhs.name
|
||||
}
|
||||
|
||||
public static func == (lhs: LanguageViewModel, rhs: LanguageViewModel) -> Bool {
|
||||
lhs.name == rhs.name &&
|
||||
lhs.speaks == rhs.speaks
|
||||
}
|
||||
|
||||
@Published var name: String
|
||||
@Published var speaks: Bool
|
||||
|
||||
init(
|
||||
_ name: String = "",
|
||||
_ speaks: Bool = true
|
||||
) {
|
||||
self.name = name
|
||||
self.speaks = speaks
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: figure out how to add this to the set of known transformers so it will work with transformer set to NSSecureUnarchiveFromDataTransformerName
|
||||
@objc(LanguageViewModelValueTransformer)
|
||||
public final class LanguageViewModelValueTransformer: 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 `LanguageViewModel` 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: LanguageViewModel.self, from: data as Data)
|
||||
return language
|
||||
} catch {
|
||||
assertionFailure("Failed to transform `Data` to `LanguageViewModel`")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -698,8 +698,51 @@ public class Monster: NSManagedObject {
|
||||
|
||||
var languagesDescription: String {
|
||||
get {
|
||||
let sortedLanguages = self.languagesArray.sorted()
|
||||
return StringHelper.oxfordJoin(sortedLanguages, ", ", ", and ", " and ")
|
||||
let spokenLanguages = (self.languages ?? [])
|
||||
.filter({ $0.speaks })
|
||||
.map({$0.name})
|
||||
.sorted()
|
||||
let understoodLanguages = (self.languages ?? [])
|
||||
.filter({ !$0.speaks })
|
||||
.map({$0.name})
|
||||
.sorted()
|
||||
|
||||
let understandsButText = understandsBut?.isEmpty ?? false
|
||||
? ""
|
||||
: String(format: " but %@", understandsBut!)
|
||||
|
||||
let telepathyText = telepathy > 0
|
||||
? String(format: ", telepathy %d ft.", telepathy)
|
||||
: ""
|
||||
|
||||
if (spokenLanguages.count > 0) {
|
||||
if (understoodLanguages.count > 0) {
|
||||
return String(
|
||||
format:"%@ and understands %@%@%@",
|
||||
StringHelper.oxfordJoin(spokenLanguages),
|
||||
StringHelper.oxfordJoin(understoodLanguages),
|
||||
understandsButText,
|
||||
telepathyText)
|
||||
} else {
|
||||
return String(
|
||||
format: "%@%@%@",
|
||||
StringHelper.oxfordJoin(spokenLanguages),
|
||||
understandsButText,
|
||||
telepathyText)
|
||||
}
|
||||
} else {
|
||||
if (understoodLanguages.count > 0) {
|
||||
return String(
|
||||
format: "understands %@%@%@",
|
||||
StringHelper.oxfordJoin(understoodLanguages),
|
||||
understandsButText,
|
||||
telepathyText)
|
||||
} else if (telepathy > 0){
|
||||
return String(format: "telepathy %d ft.", telepathy)
|
||||
} else {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -54,6 +54,9 @@ class MonsterViewModel: ObservableObject {
|
||||
@Published var damageVulnerabilities: [StringViewModel]
|
||||
@Published var conditionImmunities: [StringViewModel]
|
||||
@Published var senses: [StringViewModel]
|
||||
@Published var languages: [LanguageViewModel]
|
||||
@Published var telepathy: Int64
|
||||
@Published var understandsBut: String
|
||||
|
||||
init(_ rawMonster: Monster? = nil) {
|
||||
self.name = ""
|
||||
@@ -100,6 +103,9 @@ class MonsterViewModel: ObservableObject {
|
||||
self.damageVulnerabilities = []
|
||||
self.conditionImmunities = []
|
||||
self.senses = []
|
||||
self.languages = []
|
||||
self.telepathy = 0
|
||||
self.understandsBut = ""
|
||||
|
||||
if (rawMonster != nil) {
|
||||
self.copyFromMonster(monster: rawMonster!)
|
||||
@@ -145,6 +151,8 @@ class MonsterViewModel: ObservableObject {
|
||||
self.charismaScore = monster.charismaScore
|
||||
self.charismaSavingThrowAdvantage = monster.charismaSavingThrowAdvantageEnum
|
||||
self.charismaSavingThrowProficiency = monster.charismaSavingThrowProficiencyEnum
|
||||
self.telepathy = monster.telepathy
|
||||
self.understandsBut = monster.understandsBut ?? ""
|
||||
self.skills = (monster.skills?.allObjects.map {SkillViewModel(($0 as! Skill))})!.sorted()
|
||||
|
||||
self.damageImmunities = (monster.damageImmunities ?? [])
|
||||
@@ -166,6 +174,9 @@ class MonsterViewModel: ObservableObject {
|
||||
self.senses = (monster.senses ?? [])
|
||||
.map {StringViewModel($0)}
|
||||
.sorted()
|
||||
|
||||
self.languages = (monster.languages ?? [])
|
||||
.sorted()
|
||||
}
|
||||
|
||||
func copyToMonster(monster: Monster) {
|
||||
@@ -207,6 +218,8 @@ class MonsterViewModel: ObservableObject {
|
||||
monster.charismaScore = charismaScore
|
||||
monster.charismaSavingThrowAdvantageEnum = charismaSavingThrowAdvantage
|
||||
monster.charismaSavingThrowProficiencyEnum = charismaSavingThrowProficiency
|
||||
monster.telepathy = telepathy
|
||||
monster.understandsBut = understandsBut
|
||||
|
||||
// Remove missing skills from raw monster
|
||||
monster.skills?.forEach {s in
|
||||
@@ -233,5 +246,6 @@ class MonsterViewModel: ObservableObject {
|
||||
monster.damageResistances = damageResistances.map {$0.name}
|
||||
monster.damageVulnerabilities = damageVulnerabilities.map {$0.name}
|
||||
monster.senses = senses.map {$0.name}
|
||||
monster.languages = languages.map {LanguageViewModel($0.name, $0.speaks)}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
<attribute name="intelligenceSavingThrowProficiency" attributeType="String" defaultValueString="none"/>
|
||||
<attribute name="intelligenceScore" attributeType="Integer 64" defaultValueString="10" usesScalarValueType="YES"/>
|
||||
<attribute name="isBlind" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<attribute name="languages" optional="YES" attributeType="Transformable" valueTransformerName="LanguageViewModelValueTransformer" customClassName="[LanguageViewModel]"/>
|
||||
<attribute name="name" attributeType="String" defaultValueString="Unnamed Monster"/>
|
||||
<attribute name="naturalArmorBonus" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="otherArmorDescription" attributeType="String" defaultValueString=""/>
|
||||
@@ -47,6 +48,7 @@
|
||||
<attribute name="strengthScore" attributeType="Integer 64" defaultValueString="10" usesScalarValueType="YES"/>
|
||||
<attribute name="subtype" attributeType="String" defaultValueString=""/>
|
||||
<attribute name="swimSpeed" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="telepathy" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="tremorsenseDistance" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="truesightDistance" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="type" attributeType="String" defaultValueString=""/>
|
||||
@@ -64,7 +66,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="839"/>
|
||||
<element name="Monster" positionX="-63" positionY="-18" width="128" height="869"/>
|
||||
<element name="Skill" positionX="-63" positionY="135" width="128" height="14"/>
|
||||
</elements>
|
||||
</model>
|
||||
@@ -38,19 +38,6 @@ struct PersistenceController {
|
||||
}
|
||||
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
|
||||
if let error = error as NSError? {
|
||||
|
||||
// NSPersistentStoreCoordinator.destroyPersistentStore(storeDes)
|
||||
// Replace this implementation with code to handle the error appropriately.
|
||||
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
|
||||
|
||||
/*
|
||||
Typical reasons for an error here include:
|
||||
* The parent directory does not exist, cannot be created, or disallows writing.
|
||||
* The persistent store is not accessible, due to permissions or data protection when the device is locked.
|
||||
* The device is out of space.
|
||||
* The store could not be migrated to the current model version.
|
||||
Check the error message to determine what the actual problem was.
|
||||
*/
|
||||
fatalError("Unresolved error \(error), \(error.userInfo)")
|
||||
}
|
||||
})
|
||||
|
||||
28
iOS/MonsterCards/Views/EditLanguage.swift
Normal file
28
iOS/MonsterCards/Views/EditLanguage.swift
Normal file
@@ -0,0 +1,28 @@
|
||||
//
|
||||
// EditLanguage.swift
|
||||
// MonsterCards
|
||||
//
|
||||
// Created by Tom Hicks on 3/24/21.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct EditLanguage: View {
|
||||
@ObservedObject var viewModel: LanguageViewModel
|
||||
|
||||
var body: some View {
|
||||
MCTextField(
|
||||
label: "Name",
|
||||
value: $viewModel.name)
|
||||
.autocapitalization(.none)
|
||||
|
||||
Toggle("Speaks", isOn: $viewModel.speaks)
|
||||
}
|
||||
}
|
||||
|
||||
struct EditLanguage_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
let viewModel = LanguageViewModel()
|
||||
EditLanguage(viewModel: viewModel)
|
||||
}
|
||||
}
|
||||
48
iOS/MonsterCards/Views/EditLanguages.swift
Normal file
48
iOS/MonsterCards/Views/EditLanguages.swift
Normal file
@@ -0,0 +1,48 @@
|
||||
//
|
||||
// EditLanguages.swift
|
||||
// MonsterCards
|
||||
//
|
||||
// Created by Tom Hicks on 3/24/21.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct EditLanguages: View {
|
||||
@ObservedObject var viewModel: MonsterViewModel
|
||||
|
||||
var body: some View {
|
||||
let sortedLanguages = viewModel.languages.sorted()
|
||||
List {
|
||||
MCTextField(
|
||||
label: "Understands But",
|
||||
value: $viewModel.understandsBut)
|
||||
MCStepperField(label: "Telepathy", prefix: "", step: 5, suffix: " ft.", value: $viewModel.telepathy)
|
||||
ForEach(sortedLanguages/*viewModel.languages*/) { language in
|
||||
NavigationLink(language.name, destination: EditLanguage(viewModel: language))
|
||||
}
|
||||
|
||||
}
|
||||
.toolbar(content: {
|
||||
Button(
|
||||
action: {
|
||||
let newLanguage = LanguageViewModel("English")
|
||||
viewModel.languages.append(newLanguage)
|
||||
viewModel.languages = viewModel.languages.sorted()
|
||||
},
|
||||
label: {
|
||||
Image(systemName: "plus")
|
||||
}
|
||||
)
|
||||
})
|
||||
.onAppear(perform: {
|
||||
viewModel.languages = viewModel.languages.sorted()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
struct EditLanguages_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
let viewModel = MonsterViewModel()
|
||||
EditLanguages(viewModel: viewModel)
|
||||
}
|
||||
}
|
||||
@@ -65,6 +65,10 @@ struct EditMonster: View {
|
||||
NavigationLink(
|
||||
"Senses",
|
||||
destination: EditStrings(viewModel: monsterViewModel, path: \.senses, title: "Senses"))
|
||||
|
||||
NavigationLink(
|
||||
"Languages",
|
||||
destination: EditLanguages(viewModel: monsterViewModel))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -302,6 +302,11 @@ struct MonsterDetail_Previews: PreviewProvider {
|
||||
monster.wisdomSavingThrowProficiencyEnum = ProficiencyType.proficient
|
||||
monster.charismaSavingThrowAdvantageEnum = AdvantageType.disadvantage
|
||||
monster.charismaSavingThrowProficiencyEnum = ProficiencyType.none
|
||||
monster.telepathy = 1
|
||||
monster.languages = [
|
||||
LanguageViewModel("English", true),
|
||||
LanguageViewModel("French", false)
|
||||
]
|
||||
|
||||
return Group {
|
||||
MonsterDetail(monster: monster)
|
||||
|
||||
Reference in New Issue
Block a user