diff --git a/.swiftlint.yml b/.swiftlint.yml index b99f773..6023d9d 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -5,8 +5,8 @@ opt_in_rules: - empty_count - empty_string line_length: - warning: 150 - error: 200 + warning: 300 + error: 500 function_body_length: warning: 300 error: 500 diff --git a/GamebookEngine.xcodeproj/project.pbxproj b/GamebookEngine.xcodeproj/project.pbxproj index 433d4a4..432ee77 100644 --- a/GamebookEngine.xcodeproj/project.pbxproj +++ b/GamebookEngine.xcodeproj/project.pbxproj @@ -35,6 +35,7 @@ 4451A4B7232DCD36003D9FE9 /* PreviewViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4451A4B6232DCD36003D9FE9 /* PreviewViewController.swift */; }; 4451A4BA232DCD36003D9FE9 /* MainInterface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4451A4B8232DCD36003D9FE9 /* MainInterface.storyboard */; }; 4451A4BE232DCD36003D9FE9 /* GamebookPreviewExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 4451A4B2232DCD36003D9FE9 /* GamebookPreviewExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; + 44764DB829E1535C00CD95DD /* HelpView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44764DB729E1535C00CD95DD /* HelpView.swift */; }; 44ADBA8623404BBB00855649 /* fileicon-iphone-44x58.png in Resources */ = {isa = PBXBuildFile; fileRef = 44ADBA8223404BBA00855649 /* fileicon-iphone-44x58.png */; }; 44ADBA8723404BBB00855649 /* fileicon-ipad-64px.png in Resources */ = {isa = PBXBuildFile; fileRef = 44ADBA8323404BBB00855649 /* fileicon-ipad-64px.png */; }; 44ADBA8823404BBB00855649 /* fileicon-iphone-22x29.png in Resources */ = {isa = PBXBuildFile; fileRef = 44ADBA8423404BBB00855649 /* fileicon-iphone-22x29.png */; }; @@ -47,7 +48,6 @@ B402FFEF2315FEFA00900020 /* MarkdownEditorViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = B402FFED2315FEFA00900020 /* MarkdownEditorViewController.xib */; }; B402FFF22316055000900020 /* BRMarkdownParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = B402FFF12316055000900020 /* BRMarkdownParser.swift */; }; B402FFF5231613FA00900020 /* GameSerializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = B402FFF4231613FA00900020 /* GameSerializer.swift */; }; - B407897F2313587200D09F87 /* Help.md in Resources */ = {isa = PBXBuildFile; fileRef = B407897E2313587100D09F87 /* Help.md */; }; B407898223136E2F00D09F87 /* DecisionEditorRuleTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B407898023136E2F00D09F87 /* DecisionEditorRuleTableViewCell.swift */; }; B407898323136E2F00D09F87 /* DecisionEditorRuleTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = B407898123136E2F00D09F87 /* DecisionEditorRuleTableViewCell.xib */; }; B43EE2F0231F3FF7005D563D /* GameOverviewViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B43EE2EF231F3FF7005D563D /* GameOverviewViewController.swift */; }; @@ -87,8 +87,6 @@ B4F7C1452311ACDC00EE055C /* Page+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4F7C1432311ACDC00EE055C /* Page+CoreDataProperties.swift */; }; B4F7C1482311AEB800EE055C /* PageEditorConsequenceTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4F7C1462311AEB800EE055C /* PageEditorConsequenceTableViewCell.swift */; }; B4F7C1492311AEB800EE055C /* PageEditorConsequenceTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = B4F7C1472311AEB800EE055C /* PageEditorConsequenceTableViewCell.xib */; }; - B4F7C14C2311B3E800EE055C /* HelpViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4F7C14A2311B3E700EE055C /* HelpViewController.swift */; }; - B4F7C14D2311B3E800EE055C /* HelpViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = B4F7C14B2311B3E800EE055C /* HelpViewController.xib */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -143,6 +141,7 @@ 4451A4B6232DCD36003D9FE9 /* PreviewViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreviewViewController.swift; sourceTree = ""; }; 4451A4B9232DCD36003D9FE9 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/MainInterface.storyboard; sourceTree = ""; }; 4451A4BB232DCD36003D9FE9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 44764DB729E1535C00CD95DD /* HelpView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HelpView.swift; sourceTree = ""; }; 44ADBA8223404BBA00855649 /* fileicon-iphone-44x58.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "fileicon-iphone-44x58.png"; sourceTree = ""; }; 44ADBA8323404BBB00855649 /* fileicon-ipad-64px.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "fileicon-ipad-64px.png"; sourceTree = ""; }; 44ADBA8423404BBB00855649 /* fileicon-iphone-22x29.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "fileicon-iphone-22x29.png"; sourceTree = ""; }; @@ -155,7 +154,6 @@ B402FFED2315FEFA00900020 /* MarkdownEditorViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MarkdownEditorViewController.xib; sourceTree = ""; }; B402FFF12316055000900020 /* BRMarkdownParser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BRMarkdownParser.swift; sourceTree = ""; }; B402FFF4231613FA00900020 /* GameSerializer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GameSerializer.swift; sourceTree = ""; }; - B407897E2313587100D09F87 /* Help.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = Help.md; sourceTree = ""; }; B407898023136E2F00D09F87 /* DecisionEditorRuleTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DecisionEditorRuleTableViewCell.swift; sourceTree = ""; }; B407898123136E2F00D09F87 /* DecisionEditorRuleTableViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = DecisionEditorRuleTableViewCell.xib; sourceTree = ""; }; B43EE2EF231F3FF7005D563D /* GameOverviewViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GameOverviewViewController.swift; sourceTree = ""; }; @@ -197,8 +195,6 @@ B4F7C1432311ACDC00EE055C /* Page+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Page+CoreDataProperties.swift"; sourceTree = ""; }; B4F7C1462311AEB800EE055C /* PageEditorConsequenceTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PageEditorConsequenceTableViewCell.swift; sourceTree = ""; }; B4F7C1472311AEB800EE055C /* PageEditorConsequenceTableViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = PageEditorConsequenceTableViewCell.xib; sourceTree = ""; }; - B4F7C14A2311B3E700EE055C /* HelpViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HelpViewController.swift; sourceTree = ""; }; - B4F7C14B2311B3E800EE055C /* HelpViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = HelpViewController.xib; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -262,7 +258,6 @@ B4F7C13F23118E4200EE055C /* Consequence Editor */, B47F7BDA2310F78000BB072A /* Attribute List */, 444358B4230C56FD00A2E004 /* Page List */, - 4497ED48232489C70038C6A9 /* Help */, ); path = Editing; sourceTree = ""; @@ -288,12 +283,10 @@ path = GamebookPreviewExtension; sourceTree = ""; }; - 4497ED48232489C70038C6A9 /* Help */ = { + 44764DB629E1534B00CD95DD /* Help */ = { isa = PBXGroup; children = ( - B4F7C14A2311B3E700EE055C /* HelpViewController.swift */, - B4F7C14B2311B3E800EE055C /* HelpViewController.xib */, - B407897E2313587100D09F87 /* Help.md */, + 44764DB729E1535C00CD95DD /* HelpView.swift */, ); path = Help; sourceTree = ""; @@ -463,6 +456,7 @@ B4789FEF23188B8E008DBE9F /* Game List */, 444358C1230C7BA800A2E004 /* Playing */, 444358BC230C789900A2E004 /* Editing */, + 44764DB629E1534B00CD95DD /* Help */, 440EF3F12323279D000A7C9F /* ContentSizedTableView.swift */, B48C4B8223332297008C77ED /* ContainerView.swift */, B48C4B8423332896008C77ED /* Alerts.swift */, @@ -628,14 +622,12 @@ B4F7C1492311AEB800EE055C /* PageEditorConsequenceTableViewCell.xib in Resources */, B47F7BDE2310F79900BB072A /* AttributeTableViewCell.xib in Resources */, 44ADBA8623404BBB00855649 /* fileicon-iphone-44x58.png in Resources */, - B4F7C14D2311B3E800EE055C /* HelpViewController.xib in Resources */, B47F7BD92310F77B00BB072A /* AttributesTableViewController.xib in Resources */, 4417DC2A2314867C00A6F96B /* RuleEditorViewController.xib in Resources */, B4789FEA231887E3008DBE9F /* GameListTableViewController.xib in Resources */, 444358BA230C665E00A2E004 /* PagesTableViewController.xib in Resources */, B4B6B3BA23174CBD00E72320 /* MetadataEditorViewController.xib in Resources */, B402FFEF2315FEFA00900020 /* MarkdownEditorViewController.xib in Resources */, - B407897F2313587200D09F87 /* Help.md in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -696,8 +688,8 @@ 4439E662230B534D00C6A23C /* Consequence+CoreDataClass.swift in Sources */, 4439E65D230B534D00C6A23C /* Game+CoreDataProperties.swift in Sources */, B48C4B8523332896008C77ED /* Alerts.swift in Sources */, - B4F7C14C2311B3E800EE055C /* HelpViewController.swift in Sources */, B4A13AD5230F6D24004929B8 /* PageEditorDecisionTableViewCell.swift in Sources */, + 44764DB829E1535C00CD95DD /* HelpView.swift in Sources */, B48C4B8323332297008C77ED /* ContainerView.swift in Sources */, B448874F23063A0D000E2FDD /* AppDelegate.swift in Sources */, B4B6B3B523170B9F00E72320 /* CodableModels.swift in Sources */, diff --git a/GamebookEngine/Views/Editing/Game Overview/GameOverviewViewController.swift b/GamebookEngine/Views/Editing/Game Overview/GameOverviewViewController.swift index ce1ede4..20fa493 100644 --- a/GamebookEngine/Views/Editing/Game Overview/GameOverviewViewController.swift +++ b/GamebookEngine/Views/Editing/Game Overview/GameOverviewViewController.swift @@ -39,6 +39,10 @@ class GameOverviewViewController: UIViewController, PagesTableViewDelegate { navigationItem.leftBarButtonItem = exitButton navigationItem.rightBarButtonItem = metaButton + navigationItem.backBarButtonItem = UIBarButtonItem( + title: "Overview", style: .plain, target: nil, action: nil + ) + searchButton = UIButton() searchButton.translatesAutoresizingMaskIntoConstraints = false searchButton.addTarget(self, action: #selector(searchButtonTapped), for: .touchUpInside) diff --git a/GamebookEngine/Views/Editing/Help/Help.md b/GamebookEngine/Views/Editing/Help/Help.md deleted file mode 100644 index 2d02791..0000000 --- a/GamebookEngine/Views/Editing/Help/Help.md +++ /dev/null @@ -1,29 +0,0 @@ -# Building Gamebooks - -There are several core building blocks that should be understood to make games: Attributes, Pages, Decisions, and Consequences. Let's talk about them! - -## Attributes - -Attributes are values that you want to track changes to as the game progresses. They're simply a numerical value that you can manipulate in various ways as the player progresses through the game. - -Consequences are assigned to a Page to manipulate Attributes. - -## Pages - -Pages are the core building block of any gamebook: a gamebook is composed of a series of Pages, linked to together by Decisions. At the bottom of every Page, the list of available Decisions is shown to the player for them to choose between. - -## Decisions - -Decisions link to other Pages. Their availability on a page can be determined by checking the value of Attributes (by setting up Rules), allowing you to create dynamic gamebooks that change in subtle ways due to the player's decisions. - -## Consequences - -Consequences are assigned on the Page level and manipulate the player's Attribute values when they land on that page. - -For example, on the first page you could `Set Health to 100`, and if the player is wounded on a Page, you could create a Consequence on that page which will `Subtract Health by 20`, to create a record that the player is now down to `80 Health`. - -On a later page, you could create a Decision that has a rule for `Health is less than 100` that allows the player to ask for aid. You can use this functionality in all sorts of ways, to track relationships the player has to other characters, whether they've experienced certain events, or much more. The possibilities are endless! - -# Distributing Gamebooks - -You can export your Gamebook to a file, which contains all the information about your gamebook in the JSON format. You can use this to share your game with friends or family, they just need to download BRGamebookEngine and import the file. diff --git a/GamebookEngine/Views/Editing/Help/HelpViewController.swift b/GamebookEngine/Views/Editing/Help/HelpViewController.swift deleted file mode 100644 index f59cba8..0000000 --- a/GamebookEngine/Views/Editing/Help/HelpViewController.swift +++ /dev/null @@ -1,24 +0,0 @@ -// -// HelpViewController.swift -// BRGamebookEngine -// -// Created by Bradley Root on 8/24/19. -// Copyright © 2019 Brad Root. All rights reserved. -// - -import UIKit - -class HelpViewController: UIViewController { - @IBOutlet var textView: UITextView! - - override func viewDidLoad() { - super.viewDidLoad() - - title = "Editor Help" - guard let readMeURL = Bundle.main.url(forResource: "Help", withExtension: "md"), - let readMeContents = try? String(contentsOf: readMeURL) - else { return } - - textView.attributedText = BRMarkdownParser.standard.convertToAttributedString(readMeContents, with: .normal) - } -} diff --git a/GamebookEngine/Views/Editing/Help/HelpViewController.xib b/GamebookEngine/Views/Editing/Help/HelpViewController.xib deleted file mode 100644 index 742c335..0000000 --- a/GamebookEngine/Views/Editing/Help/HelpViewController.xib +++ /dev/null @@ -1,54 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/GamebookEngine/Views/Editing/Page Editor/PageEditorViewController.swift b/GamebookEngine/Views/Editing/Page Editor/PageEditorViewController.swift index b916f92..c3072d2 100644 --- a/GamebookEngine/Views/Editing/Page Editor/PageEditorViewController.swift +++ b/GamebookEngine/Views/Editing/Page Editor/PageEditorViewController.swift @@ -6,6 +6,7 @@ // Copyright © 2019 Brad Root. All rights reserved. // +import SwiftUI import UIKit protocol PageEditorDelegate: AnyObject { @@ -122,11 +123,11 @@ class PageEditorViewController: UIViewController { addButton = UIBarButtonItem(title: "Add", style: .plain, target: self, action: #selector(showAddActionSheet)) backButton = UIBarButtonItem(title: "Prev Page", style: .plain, target: self, action: #selector(goToPreviousPage)) - mapButton = UIBarButtonItem(title: "Overview", style: .plain, target: self, action: #selector(exitAction)) - helpButton = UIBarButtonItem(title: "Help", style: .plain, target: self, action: #selector(helpAction)) + helpButton = UIBarButtonItem(image: UIImage(systemName: "questionmark.circle"), style: .plain, target: self, action: #selector(helpAction)) + navigationItem.leftItemsSupplementBackButton = true navigationItem.rightBarButtonItems = [addButton, backButton] - navigationItem.leftBarButtonItems = [mapButton, helpButton] + navigationItem.leftBarButtonItems = [helpButton] navigationItem.largeTitleDisplayMode = .never @@ -218,7 +219,10 @@ class PageEditorViewController: UIViewController { } @objc func helpAction() { - navigationController?.pushViewController(HelpViewController(), animated: true) + let swiftUIViewController = UIHostingController(rootView: HelpView()) + swiftUIViewController.modalPresentationStyle = .pageSheet +// present(swiftUIViewController, animated: true, completion: nil) + navigationController?.pushViewController(swiftUIViewController, animated: true) } @objc func exitAction() { diff --git a/GamebookEngine/Views/Game List/GameListTableViewController.swift b/GamebookEngine/Views/Game List/GameListTableViewController.swift index f46c4f2..1038d33 100644 --- a/GamebookEngine/Views/Game List/GameListTableViewController.swift +++ b/GamebookEngine/Views/Game List/GameListTableViewController.swift @@ -18,14 +18,9 @@ class GameListTableViewController: UITableViewController { @IBOutlet var patronButton: UIButton! @IBAction func patronButtonAction(_: UIButton) { - Log.debug("Tapped on website button.") - UIApplication.shared.open( - URL( - string: "https://amiantos.net?utm_source=gamebook_ios&utm_medium=button&utm_campaign=game_list" - )!, - options: [:], - completionHandler: nil - ) + let swiftUIViewController = UIHostingController(rootView: HelpView()) + swiftUIViewController.modalPresentationStyle = .pageSheet + present(swiftUIViewController, animated: true, completion: nil) } @IBAction func topBarAddAction(_ sender: UIButton) { @@ -46,11 +41,7 @@ class GameListTableViewController: UITableViewController { override func viewWillAppear(_ animated: Bool) { fetchGames() super.viewWillAppear(animated) - patronButton.layer.cornerRadius = 10 - patronButton.layer.shadowRadius = 10 - patronButton.layer.shadowOffset = .zero - patronButton.layer.shadowOpacity = 0.1 } override func viewDidAppear(_ animated: Bool) { diff --git a/GamebookEngine/Views/Game List/GameListTableViewController.xib b/GamebookEngine/Views/Game List/GameListTableViewController.xib index 405101d..1b7ba52 100644 --- a/GamebookEngine/Views/Game List/GameListTableViewController.xib +++ b/GamebookEngine/Views/Game List/GameListTableViewController.xib @@ -1,18 +1,19 @@ - + - + + - + @@ -21,10 +22,10 @@ + - - + @@ -36,23 +37,23 @@ - + - - + + + + + + + + + + + + + + + + + + + + - + + + + + - Gamebook Engine is free, open source software created by Brad Root. If you like it, check out my website to see other apps I've created and read about what I'm working on every week. - - - - - + + - - + - - - + + + - - + - + - + - + + + + + + + + + + diff --git a/GamebookEngine/Views/Help/HelpView.swift b/GamebookEngine/Views/Help/HelpView.swift new file mode 100644 index 0000000..1da1319 --- /dev/null +++ b/GamebookEngine/Views/Help/HelpView.swift @@ -0,0 +1,79 @@ +// +// HelpView.swift +// GamebookEngine +// +// Created by Brad Root on 4/8/23. +// Copyright © 2023 Brad Root. All rights reserved. +// + +import SwiftUI + +struct HelpContainer: View { + @Environment(\.openURL) var openURL + + let title: String + let content: String + let url: URL + let cta: String + + var body: some View { + VStack { + Text(title) + .multilineTextAlignment(.leading) + .frame(maxWidth: .infinity, alignment: .leading) + .font(.title) + .fixedSize(horizontal: false, vertical: true) + .padding(EdgeInsets(top: 22, leading: 22, bottom: 4, trailing: 22)) + + Text(content) + .fixedSize(horizontal: false, vertical: true) + .frame(maxWidth: .infinity, alignment: .leading) + .font(.subheadline) + .padding(EdgeInsets(top: 0, leading: 22, bottom: 8, trailing: 22)) + + Button { + openURL(url) + } label: { + Text(cta) + .fontWeight(.medium) + .foregroundColor(Color("button")) + .frame(maxWidth: .infinity, alignment: .center) + .padding(EdgeInsets(top: 6, leading: 0, bottom: 8, trailing: 0)) + .background(Color("background")) + .cornerRadius(5) + .padding(EdgeInsets(top: 0, leading: 22, bottom: 22, trailing: 22)) + } + } + .background(Color("containerBackground")) + .foregroundColor(Color("text")) + .cornerRadius(10) + .padding(EdgeInsets(top: 10, leading: 20, bottom: 10, trailing: 20)) + .shadow(color: Color(white: 0, opacity: 0.1), radius: 10) + } +} + +struct HelpView: View { + var body: some View { + NavigationView { + ScrollView { + VStack { + HelpContainer(title: "Documentation", content: "Need help understanding what a gamebook is, and how Gamebook Engine helps you write them? Check out the Wiki for a deep dive on Gamebook structure.", url: URL(string: "https://github.com/amiantos/gamebookengine/wiki")!, cta: "Go to the Wiki") + HelpContainer(title: "Report Bugs", content: "If you find bugs, GitHub Issues is the best place to report them. Gamebook Engine is on GitHub because it is free open source software. That means the source code is available online for you to look at, modify, or use in your own projects.", url: URL(string: "https://github.com/amiantos/gamebookengine/issues")!, cta: "Report Issues on GitHub") + + HelpContainer(title: "Discord Community", content: "Want to chat with the developer and other Gamebook Engine users? Did you write a great gamebook and want to get opinions on it? Join the Discord community.", url: URL(string: "https://discord.gg/QncPzv4PXc")!, cta: "Join on Discord") + + HelpContainer(title: "Email Brad", content: "If none of those other options are working out for you, you can always email me directly. My name is Brad. Say hello!", url: URL(string: "mailto:bradroot@me.com?subject=Gamebook%20Engine%20Feedback")!, cta: "Email bradroot@me.com") + } + } + .navigationTitle("Get Help") + .navigationBarTitleDisplayMode(.inline) + } + .navigationViewStyle(.stack) + } +} + +struct HelpView_Previews: PreviewProvider { + static var previews: some View { + HelpView() + } +}