diff --git a/GamebookEngine.xcodeproj/project.pbxproj b/GamebookEngine.xcodeproj/project.pbxproj index 44f6077..0a42afc 100644 --- a/GamebookEngine.xcodeproj/project.pbxproj +++ b/GamebookEngine.xcodeproj/project.pbxproj @@ -42,6 +42,7 @@ 44C522EB232F0B6D00E7AC95 /* GamePlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44C522EA232F0B6D00E7AC95 /* GamePlayer.swift */; }; 44CB58C32326CFB6009E49D9 /* An Introduction to Gamebook Engine.gbook in Resources */ = {isa = PBXBuildFile; fileRef = 44CB58C22326CFB6009E49D9 /* An Introduction to Gamebook Engine.gbook */; }; 44CB58C523286792009E49D9 /* Logging.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44CB58C423286792009E49D9 /* Logging.swift */; }; + 44F8AA9B29E12F0F0031BCBB /* GameListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44F8AA9A29E12F0F0031BCBB /* GameListView.swift */; }; B402FFEE2315FEFA00900020 /* MarkdownEditorViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B402FFEC2315FEFA00900020 /* MarkdownEditorViewController.swift */; }; B402FFEF2315FEFA00900020 /* MarkdownEditorViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = B402FFED2315FEFA00900020 /* MarkdownEditorViewController.xib */; }; B402FFF22316055000900020 /* BRMarkdownParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = B402FFF12316055000900020 /* BRMarkdownParser.swift */; }; @@ -149,6 +150,7 @@ 44C522EA232F0B6D00E7AC95 /* GamePlayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GamePlayer.swift; sourceTree = ""; }; 44CB58C22326CFB6009E49D9 /* An Introduction to Gamebook Engine.gbook */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "An Introduction to Gamebook Engine.gbook"; sourceTree = ""; }; 44CB58C423286792009E49D9 /* Logging.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Logging.swift; sourceTree = ""; }; + 44F8AA9A29E12F0F0031BCBB /* GameListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GameListView.swift; sourceTree = ""; }; B402FFEC2315FEFA00900020 /* MarkdownEditorViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MarkdownEditorViewController.swift; sourceTree = ""; }; B402FFED2315FEFA00900020 /* MarkdownEditorViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MarkdownEditorViewController.xib; sourceTree = ""; }; B402FFF12316055000900020 /* BRMarkdownParser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BRMarkdownParser.swift; sourceTree = ""; }; @@ -384,6 +386,7 @@ B4789FE8231887E3008DBE9F /* GameListTableViewController.xib */, B4789FEB2318880E008DBE9F /* GameListGameTableViewCell.swift */, B4789FEC2318880E008DBE9F /* GameListGameTableViewCell.xib */, + 44F8AA9A29E12F0F0031BCBB /* GameListView.swift */, ); path = "Game List"; sourceTree = ""; @@ -707,6 +710,7 @@ B4CB7FBA23120176009B4DF0 /* Rule+CoreDataClass.swift in Sources */, 4439E65F230B534D00C6A23C /* Decision+CoreDataProperties.swift in Sources */, 44CB58C523286792009E49D9 /* Logging.swift in Sources */, + 44F8AA9B29E12F0F0031BCBB /* GameListView.swift in Sources */, B4B6B3B923174CBD00E72320 /* MetadataEditorViewController.swift in Sources */, B4E9EFBF230B6DD500C9CA76 /* Extensions.swift in Sources */, 444358C4230C7BBE00A2E004 /* PlayViewController.swift in Sources */, @@ -920,7 +924,7 @@ CURRENT_PROJECT_VERSION = 15; DEVELOPMENT_TEAM = 2Y9M69QJKZ; INFOPLIST_FILE = GamebookEngine/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 15.6; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -942,7 +946,7 @@ CURRENT_PROJECT_VERSION = 15; DEVELOPMENT_TEAM = 2Y9M69QJKZ; INFOPLIST_FILE = GamebookEngine/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 15.6; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", diff --git a/GamebookEngine/AppDelegate.swift b/GamebookEngine/AppDelegate.swift index 6e6579b..c35f16e 100644 --- a/GamebookEngine/AppDelegate.swift +++ b/GamebookEngine/AppDelegate.swift @@ -7,6 +7,7 @@ // import CoreData +import SwiftUI import UIKit @UIApplicationMain @@ -27,7 +28,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate { window = UIWindow(frame: UIScreen.main.bounds) guard let window = window else { return false } - window.rootViewController = GameListTableViewController() +// window.rootViewController = GameListTableViewController() + window.rootViewController = UIHostingController(rootView: GameListView()) window.makeKeyAndVisible() return true } diff --git a/GamebookEngine/Extensions.swift b/GamebookEngine/Extensions.swift index 156f7b0..df8d53f 100644 --- a/GamebookEngine/Extensions.swift +++ b/GamebookEngine/Extensions.swift @@ -7,8 +7,26 @@ // import Foundation +import SwiftUI import UIKit +extension View { + /// Sets the text color for a navigation bar title. + /// - Parameter color: Color the title should be + /// + /// Supports both regular and large titles. + @available(iOS 14, *) + func navigationBarTitleTextColor(_ color: Color) -> some View { + let uiColor = UIColor(color) + + // Set appearance for both normal and large sizes. + UINavigationBar.appearance().titleTextAttributes = [.foregroundColor: uiColor] + UINavigationBar.appearance().largeTitleTextAttributes = [.foregroundColor: uiColor] + + return self + } +} + func angleBetween(pointOne: CGPoint, andPointTwo pointTwo: CGPoint) -> CGFloat { let xdiff = (pointTwo.x - pointOne.x) let ydiff = (pointTwo.y - pointOne.y) diff --git a/GamebookEngine/Views/Game List/GameListView.swift b/GamebookEngine/Views/Game List/GameListView.swift new file mode 100644 index 0000000..97ea25f --- /dev/null +++ b/GamebookEngine/Views/Game List/GameListView.swift @@ -0,0 +1,142 @@ +// +// GameListView.swift +// GamebookEngine +// +// Created by Brad Root on 4/7/23. +// Copyright © 2023 Brad Root. All rights reserved. +// + +import SwiftUI + +struct GameCard: View { + let game: Game + + var body: some View { + HStack { + VStack { + Text(game.name) + .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(game.author) + .font(.headline) + .frame(maxWidth: .infinity, alignment: .leading) + .foregroundColor(.secondary) + .padding(EdgeInsets(top: 0, leading: 22, bottom: 8, trailing: 22)) + + Text(game.about ?? "") + .font(.subheadline) + .frame(maxWidth: .infinity, alignment: .leading) + .padding(EdgeInsets(top: 0, leading: 22, bottom: 8, trailing: 22)) + + Text("Play Gamebook") + .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: 20, leading: 20, bottom: 20, trailing: 0)) + .shadow(color: Color(white: 0, opacity: 0.1), radius: 10) + + VStack { + Button { + print("Play") + } label: { + Image("play") + .foregroundColor(Color("button")) + } + .frame(width: 50, height: 30, alignment: .center) + .buttonStyle(.borderless) + + Button { + print("Play") + } label: { + Image("edit") + .foregroundColor(Color("button")) + } + .frame(width: 50, height: 30, alignment: .center) + .buttonStyle(.borderless) + + Button { + print("Play") + } label: { + Image("export") + .foregroundColor(Color("button")) + } + .frame(width: 50, height: 30, alignment: .center) + .buttonStyle(.borderless) + + Button { + print("Play") + } label: { + Image("delete") + .foregroundColor(Color("button")) + } + .frame(width: 50, height: 30, alignment: .center) + .buttonStyle(.borderless) + } + .padding(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 10)) + } + } +} + +struct GameListView: View { + @State private var games: [Game] = [] + + var body: some View { + NavigationStack { + List(games, id: \.uuid) { game in + GameCard(game: game) + .listRowBackground(Color("background")) + .listRowInsets(EdgeInsets()) + } + .listStyle(.plain) + .foregroundColor(Color("text")) + .background(Color("background")) + .scrollContentBackground(.hidden) + .navigationTitle("Your Gamebooks") + .navigationBarTitleTextColor(.secondary) + .toolbar { + ToolbarItem(placement: .navigationBarTrailing) { + Button { + print("About tapped!") + } label: { + Image("add") + .foregroundColor(Color("button")) + } + } + ToolbarItem(placement: .navigationBarLeading) { + Button("Help") { + print("Help tapped!") + }.foregroundColor(Color("button")) + } + } + } + .onAppear(perform: fetchGames) + } + + func fetchGames() { + GameDatabase.standard.fetchGames { games in + if let games = games { + DispatchQueue.main.async { + self.games = games + } + } + } + } +} + +struct GameListView_Previews: PreviewProvider { + static var previews: some View { + GameListView() + } +}