Makes MonsterDetail use a MonsterViewModel instead of the core data type Monster.

This commit is contained in:
2021-04-04 00:30:55 -07:00
parent 027fdbd53e
commit f3544a581b
5 changed files with 74 additions and 47 deletions

View File

@@ -34,7 +34,7 @@ public class AbilityViewModel: NSObject, ObservableObject, Identifiable, NSSecur
} }
} }
public func renderedText(_ monster: Monster) -> String { func renderedText(_ monster: MonsterViewModel) -> String {
let strSave = monster.strengthModifier + monster.proficiencyBonus + 8 let strSave = monster.strengthModifier + monster.proficiencyBonus + 8
let dexSave = monster.dexterityModifier + monster.proficiencyBonus + 8 let dexSave = monster.dexterityModifier + monster.proficiencyBonus + 8
let conSave = monster.constitutionModifier + monster.proficiencyBonus + 8 let conSave = monster.constitutionModifier + monster.proficiencyBonus + 8

View File

@@ -125,4 +125,25 @@ class SkillViewModel: ObservableObject, Comparable, Hashable, Identifiable {
newSkill.wrappedAdvantage = advantage newSkill.wrappedAdvantage = advantage
return newSkill return newSkill
} }
func modifier(forMonster: MonsterViewModel) -> Int {
let proficiencyBonus = Double(forMonster.proficiencyBonus)
let abilityScoreModifier = Double(forMonster.abilityModifierForAbilityScore(abilityScore))
switch proficiency {
case .none:
return Int(abilityScoreModifier)
case .proficient:
return Int(abilityScoreModifier + proficiencyBonus)
case .expertise:
return Int(abilityScoreModifier + 2 * proficiencyBonus)
}
}
func skillDescription(forMonster: MonsterViewModel) -> String {
var advantageLabel = Monster.advantageLabelStringForType(advantage)
if (advantageLabel != "") {
advantageLabel = " " + advantageLabel
}
return String(format: "%@ %+d%@", name, modifier(forMonster: forMonster), advantageLabel)
}
} }

View File

@@ -20,7 +20,7 @@ struct Library: View {
var body: some View { var body: some View {
NavigationView{ NavigationView{
List(allMonsters) { monster in List(allMonsters) { monster in
NavigationLink(destination: MonsterDetail(monster: monster)) { NavigationLink(destination: MonsterDetailWrapper(monster: monster)) {
Text(monster.name ?? "") Text(monster.name ?? "")
} }
} }

View File

@@ -72,7 +72,7 @@ struct SmallAbilityScore: View {
} }
struct BasicInfoView: View { struct BasicInfoView: View {
@ObservedObject var monster: Monster @ObservedObject var monster: MonsterViewModel
var body: some View { var body: some View {
let monsterMeta = monster.meta let monsterMeta = monster.meta
@@ -113,7 +113,7 @@ struct BasicInfoView: View {
} }
struct AbilityScoresView: View { struct AbilityScoresView: View {
@ObservedObject var monster: Monster @ObservedObject var monster: MonsterViewModel
var body: some View { var body: some View {
SectionDivider() SectionDivider()
@@ -131,7 +131,7 @@ struct AbilityScoresView: View {
} }
struct ResistancesAndImmunitiesView: View { struct ResistancesAndImmunitiesView: View {
@ObservedObject var monster: Monster @ObservedObject var monster: MonsterViewModel
var body: some View { var body: some View {
let monsterDamageVulnerabilitiesDescription = monster.damageVulnerabilitiesDescription let monsterDamageVulnerabilitiesDescription = monster.damageVulnerabilitiesDescription
@@ -178,7 +178,7 @@ struct ResistancesAndImmunitiesView: View {
} }
struct SavingThrowsAndSkillsView: View { struct SavingThrowsAndSkillsView: View {
@ObservedObject var monster: Monster @ObservedObject var monster: MonsterViewModel
var body: some View { var body: some View {
let savingThrowsDescription = monster.savingThrowsDescription let savingThrowsDescription = monster.savingThrowsDescription
@@ -200,37 +200,28 @@ struct SavingThrowsAndSkillsView: View {
} }
} }
struct MonsterDetail: View { struct MonsterDetailView: View {
let kTextColor: Color = Color(hex: 0x982818) let kTextColor = Color(hex: 0x982818)
@ObservedObject var monster: Monster var viewModel: MonsterViewModel
var body: some View { var body: some View {
let monsterLanguagesDescription = viewModel.languagesDescription
let monsterChallengeRatingDescription = viewModel.challengeRatingDescription
ScrollView { ScrollView {
// TODO: Consider adding an inmage here at the top // TODO: Consider adding an inmage here at the top
VStack (alignment: .leading) { VStack (alignment: .leading) {
let monsterLanguagesDescription = monster.languagesDescription
let monsterChallengeRatingDescription = monster.challengeRatingDescription
let monsterAbilities: [AbilityViewModel] = monster.abilities ?? []
let monsterActions: [AbilityViewModel] = monster.actions ?? []
let monsterLegendaryActions: [AbilityViewModel] = monster.legendaryActions ?? []
BasicInfoView(monster: monster)
// 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
AbilityScoresView(monster: monster)
BasicInfoView(monster: viewModel)
AbilityScoresView(monster: viewModel)
SectionDivider() SectionDivider()
SavingThrowsAndSkillsView(monster: viewModel)
SavingThrowsAndSkillsView(monster: monster) ResistancesAndImmunitiesView(monster: viewModel)
ResistancesAndImmunitiesView(monster: monster)
Group { Group {
// Languages // Languages
if (!monsterLanguagesDescription.isEmpty) { if (!monsterLanguagesDescription.isEmpty) {
@@ -248,27 +239,27 @@ struct MonsterDetail: View {
// Proficiency Bonus // Proficiency Bonus
LabeledField("Proficiency Bonus") { LabeledField("Proficiency Bonus") {
Text(String(monster.proficiencyBonus)) Text(String(viewModel.proficiencyBonus))
} }
// Abilities // Abilities
if (monsterAbilities.count > 0) { if (viewModel.abilities.count > 0) {
ForEach(monsterAbilities) { ability in ForEach(viewModel.abilities) { ability in
VStack { VStack {
Markdown(Document(ability.renderedText(monster))) Markdown(Document(ability.renderedText(viewModel)))
Divider() Divider()
} }
} }
} }
// Actions // Actions
if (monsterActions.count > 0) { if (viewModel.actions.count > 0) {
VStack(alignment: .leading) { VStack(alignment: .leading) {
Text("Actions") Text("Actions")
.font(.system(size: 24, weight: .bold)) .font(.system(size: 24, weight: .bold))
ForEach(monsterActions) { action in ForEach(viewModel.actions) { action in
VStack { VStack {
Markdown(Document(action.renderedText(monster))) Markdown(Document(action.renderedText(viewModel)))
Divider() Divider()
} }
} }
@@ -276,13 +267,13 @@ struct MonsterDetail: View {
} }
// Legendary Actions // Legendary Actions
if (monsterLegendaryActions.count > 0) { if (viewModel.legendaryActions.count > 0) {
VStack(alignment: .leading) { VStack(alignment: .leading) {
Text("Legendary Actions") Text("Legendary Actions")
.font(.system(size: 20, weight: .bold)) .font(.system(size: 20, weight: .bold))
ForEach(monsterLegendaryActions) { action in ForEach(viewModel.legendaryActions) { action in
VStack { VStack {
Markdown(Document(action.renderedText(monster))) Markdown(Document(action.renderedText(viewModel)))
Divider() Divider()
} }
} }
@@ -293,13 +284,28 @@ struct MonsterDetail: View {
.padding(.horizontal) .padding(.horizontal)
.foregroundColor(kTextColor) .foregroundColor(kTextColor)
} }
.toolbar(content: { }
ToolbarItem(placement: .primaryAction) { }
NavigationLink("Edit", destination: EditMonster(monster: monster))
} struct MonsterDetailWrapper: View {
}) let kTextColor: Color = Color(hex: 0x982818)
.navigationTitle(monster.name ?? "")
.navigationBarTitleDisplayMode(.inline) @ObservedObject var monster: Monster
@StateObject private var viewModel = MonsterViewModel()
var body: some View {
MonsterDetailView(viewModel: viewModel)
.onAppear(perform: {
viewModel.copyFromMonster(monster: monster)
})
.toolbar(content: {
ToolbarItem(placement: .primaryAction) {
NavigationLink("Edit", destination: EditMonster(monster: monster))
}
})
.navigationTitle(monster.name ?? "")
.navigationBarTitleDisplayMode(.inline)
} }
private func editMonster() { private func editMonster() {
@@ -307,7 +313,7 @@ struct MonsterDetail: View {
} }
} }
struct MonsterDetail_Previews: PreviewProvider { struct MonsterDetailWrapper_Previews: PreviewProvider {
static var previews: some View { static var previews: some View {
let context = PersistenceController.preview.container.viewContext let context = PersistenceController.preview.container.viewContext
let monster = Monster.init(context: context) let monster = Monster.init(context: context)
@@ -352,10 +358,10 @@ struct MonsterDetail_Previews: PreviewProvider {
] ]
return Group { return Group {
MonsterDetail(monster: monster) MonsterDetailWrapper(monster: monster)
.environment(\.managedObjectContext, context) .environment(\.managedObjectContext, context)
.previewDevice("iPod touch (7th generation)") .previewDevice("iPod touch (7th generation)")
MonsterDetail(monster: monster) MonsterDetailWrapper(monster: monster)
.environment(\.managedObjectContext, context) .environment(\.managedObjectContext, context)
.previewDevice("iPad Pro (11-inch) (2nd generation)") .previewDevice("iPad Pro (11-inch) (2nd generation)")
} }

View File

@@ -59,7 +59,7 @@ struct Search: View {
return false return false
})) { monster in })) { monster in
NavigationLink(destination: MonsterDetail(monster: monster)) { NavigationLink(destination: MonsterDetailWrapper(monster: monster)) {
Text(monster.name ?? "") Text(monster.name ?? "")
} }
} }