diff --git a/RIT Dining.xcodeproj/project.pbxproj b/RIT Dining.xcodeproj/project.pbxproj index 2d9fd7a..70336ab 100644 --- a/RIT Dining.xcodeproj/project.pbxproj +++ b/RIT Dining.xcodeproj/project.pbxproj @@ -78,7 +78,7 @@ attributes = { BuildIndependentTargetsInParallel = 1; LastSwiftUpdateCheck = 1640; - LastUpgradeCheck = 1640; + LastUpgradeCheck = 2600; TargetAttributes = { 376AE05A2E6495EB00AB698B = { CreatedOnToolsVersion = 16.4; @@ -186,6 +186,7 @@ MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; + STRING_CATALOG_GENERATE_SYMBOLS = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; }; @@ -243,6 +244,7 @@ MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = iphoneos; + STRING_CATALOG_GENERATE_SYMBOLS = YES; SWIFT_COMPILATION_MODE = wholemodule; VALIDATE_PRODUCT = YES; }; @@ -255,10 +257,13 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 6; + CURRENT_PROJECT_VERSION = 8; DEVELOPMENT_TEAM = 5GF7GKNTK4; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_CFBundleDisplayName = "RIT Dining"; + INFOPLIST_KEY_ITSAppUsesNonExemptEncryption = NO; + INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities"; INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchScreen_Generation = YES; @@ -286,10 +291,13 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 6; + CURRENT_PROJECT_VERSION = 8; DEVELOPMENT_TEAM = 5GF7GKNTK4; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_CFBundleDisplayName = "RIT Dining"; + INFOPLIST_KEY_ITSAppUsesNonExemptEncryption = NO; + INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities"; INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchScreen_Generation = YES; diff --git a/RIT Dining/AboutView.swift b/RIT Dining/AboutView.swift deleted file mode 100644 index 3750ffd..0000000 --- a/RIT Dining/AboutView.swift +++ /dev/null @@ -1,29 +0,0 @@ -// -// AboutView.swift -// RIT Dining -// -// Created by Campbell on 9/12/25. -// - -import SwiftUI - -struct AboutView: View { - var body: some View { - VStack { - Image("Icon") - .resizable() - .frame(width: 128, height: 128) - .clipShape(RoundedRectangle(cornerRadius: 20)) - Text("RIT Dining App") - .font(.title) - Text("because the RIT dining website is slow!") - } - .padding() - .navigationTitle("About") - .navigationBarTitleDisplayMode(.inline) - } -} - -#Preview { - AboutView() -} diff --git a/RIT Dining/Assets.xcassets/kofiLogo.imageset/Contents.json b/RIT Dining/Assets.xcassets/kofiLogo.imageset/Contents.json new file mode 100644 index 0000000..4c7e18a --- /dev/null +++ b/RIT Dining/Assets.xcassets/kofiLogo.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "kofiLogo.png", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/RIT Dining/Assets.xcassets/kofiLogo.imageset/kofiLogo.png b/RIT Dining/Assets.xcassets/kofiLogo.imageset/kofiLogo.png new file mode 100644 index 0000000..4f93bdb Binary files /dev/null and b/RIT Dining/Assets.xcassets/kofiLogo.imageset/kofiLogo.png differ diff --git a/RIT Dining/Assets.xcassets/paypalLogo.imageset/Contents.json b/RIT Dining/Assets.xcassets/paypalLogo.imageset/Contents.json new file mode 100644 index 0000000..e83eb80 --- /dev/null +++ b/RIT Dining/Assets.xcassets/paypalLogo.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "paypalLogo.png", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/RIT Dining/Assets.xcassets/paypalLogo.imageset/paypalLogo.png b/RIT Dining/Assets.xcassets/paypalLogo.imageset/paypalLogo.png new file mode 100644 index 0000000..df99411 Binary files /dev/null and b/RIT Dining/Assets.xcassets/paypalLogo.imageset/paypalLogo.png differ diff --git a/RIT Dining/ContentView.swift b/RIT Dining/ContentView.swift index e32a854..ad88332 100644 --- a/RIT Dining/ContentView.swift +++ b/RIT Dining/ContentView.swift @@ -56,6 +56,7 @@ struct LocationList: View { struct ContentView: View { @State private var isLoading: Bool = true @State private var loadFailed: Bool = false + @State private var showingDonationSheet: Bool = false @State private var rotationDegrees: Double = 0 @State private var diningLocations: [DiningLocation] = [] @State private var lastRefreshed: Date? @@ -155,7 +156,15 @@ struct ContentView: View { } else { VStack() { List { - if searchText.isEmpty { + // Always show the visiting chef link on iOS 26+, since the bottom mounted search bar makes this work okay. On + // older iOS versions, hide the button while searching to make it easier to go through search results. + if #unavailable(iOS 26.0), searchText.isEmpty { + Section(content: { + NavigationLink(destination: VisitingChefs()) { + Text("Today's Visiting Chefs") + } + }) + } else { Section(content: { NavigationLink(destination: VisitingChefs()) { Text("Today's Visiting Chefs") @@ -196,8 +205,14 @@ struct ContentView: View { .foregroundColor(.accentColor) Text("About") } + Button(action: { + showingDonationSheet = true + }) { + Label("Donate", systemImage: "heart") + } } label: { Image(systemName: "slider.horizontal.3") + .foregroundStyle(.accent) } } } @@ -206,6 +221,9 @@ struct ContentView: View { .onAppear { getDiningData() } + .sheet(isPresented: $showingDonationSheet) { + DonationView() + } } } diff --git a/RIT Dining/FetchData.swift b/RIT Dining/Data/FetchData.swift similarity index 100% rename from RIT Dining/FetchData.swift rename to RIT Dining/Data/FetchData.swift diff --git a/RIT Dining/Types.swift b/RIT Dining/Data/Types.swift similarity index 100% rename from RIT Dining/Types.swift rename to RIT Dining/Data/Types.swift diff --git a/RIT Dining/SharedComponents.swift b/RIT Dining/SharedComponents.swift index fa36213..fbab5ca 100644 --- a/RIT Dining/SharedComponents.swift +++ b/RIT Dining/SharedComponents.swift @@ -30,3 +30,10 @@ func getAPIFriendlyDateString(date: Date) -> String { formatter.dateFormat = "yyyy-MM-dd" return formatter.string(from: date) } + + +// Custom view extension that just applies modifiers in a block to the object it's applied to. Mostly useful for splitting up conditional +// modifiers that should only be applied for certain OS versions. +extension View { + func apply(@ViewBuilder _ block: (Self) -> V) -> V { block(self) } +} diff --git a/RIT Dining/Views/AboutView.swift b/RIT Dining/Views/AboutView.swift new file mode 100644 index 0000000..85080e5 --- /dev/null +++ b/RIT Dining/Views/AboutView.swift @@ -0,0 +1,46 @@ +// +// AboutView.swift +// RIT Dining +// +// Created by Campbell on 9/12/25. +// + +import SwiftUI + +struct AboutView: View { + @Environment(\.openURL) private var openURL + let appVersionString: String = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as! String + let buildNumber: String = Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion") as! String + + var body: some View { + VStack { + Image("Icon") + .resizable() + .frame(width: 128, height: 128) + .clipShape(RoundedRectangle(cornerRadius: 20)) + Text("RIT Dining App") + .font(.title) + Text("because the RIT dining website is slow!") + Text("Version \(appVersionString) (\(buildNumber))") + .foregroundStyle(.secondary) + Spacer() + Button(action: { + openURL(URL(string: "https://github.com/NinjaCheetah/RIT-Dining")!) + }) { + Label("GitHub Repository", systemImage: "globe") + } + Button(action: { + openURL(URL(string: "https://tigercenter.rit.edu/")!) + }) { + Label("TigerCenter API", systemImage: "globe") + } + } + .padding() + .navigationTitle("About") + .navigationBarTitleDisplayMode(.inline) + } +} + +#Preview { + AboutView() +} diff --git a/RIT Dining/DetailView.swift b/RIT Dining/Views/DetailView.swift similarity index 100% rename from RIT Dining/DetailView.swift rename to RIT Dining/Views/DetailView.swift diff --git a/RIT Dining/Views/DonationView.swift b/RIT Dining/Views/DonationView.swift new file mode 100644 index 0000000..ae6498d --- /dev/null +++ b/RIT Dining/Views/DonationView.swift @@ -0,0 +1,109 @@ +// +// DonationView.swift +// RIT Dining +// +// Created by Campbell on 9/17/25. +// + +import SwiftUI + +struct DonationView: View { + @Environment(\.dismiss) var dismiss + @Environment(\.openURL) private var openURL + @State private var symbolDrawn: Bool = true + + var body: some View { + NavigationView { + VStack(alignment: .center, spacing: 12) { + HStack { + if #available(iOS 26.0, *) { + Image(systemName: "heart.fill") + .foregroundStyle(.red) + .symbolEffect(.drawOn, isActive: symbolDrawn) + .onAppear { + DispatchQueue.main.asyncAfter(deadline: .now() + 0.75) { + symbolDrawn = false + } + } + } else { + Image(systemName: "heart.fill") + .foregroundStyle(.red) + } + Text("Donate") + .fontWeight(.bold) + } + .font(.title) + Text("The RIT Dining app is free and open source software!") + .fontWeight(.bold) + .multilineTextAlignment(.center) + Text("However, the Apple Developer Program is expensive, and I paid $106.19 pretty much just to distribute this app and nothing else. If you can, I'd appreciate it if you wouldn't mind tossing a coin or two my way to help and make that expense a little less painful.") + .multilineTextAlignment(.center) + Text("No pressure though.") + .foregroundStyle(.secondary) + Button(action: { + openURL(URL(string: "https://ko-fi.com/ninjacheetah")!) + }) { + HStack(alignment: .center) { + Image("kofiLogo") + .resizable() + .frame(width: 50, height: 50) + .clipShape(RoundedRectangle(cornerRadius: 10)) + VStack(alignment: .leading) { + Text("Tip Me on Ko-fi") + .fontWeight(.bold) + Text("Chip in as much or as little as you'd like!") + .foregroundStyle(.secondary) + .multilineTextAlignment(.leading) + } + Spacer() + Image(systemName: "chevron.forward") + } + .padding(.all, 6) + .background ( + RoundedRectangle(cornerRadius: 8) + .fill(Color.secondary.opacity(0.1)) + ) + } + .buttonStyle(.plain) + Button(action: { + openURL(URL(string: "paypal.me/NinjaCheetahX")!) + }) { + HStack(alignment: .center) { + Image("paypalLogo") + .resizable() + .frame(width: 50, height: 50) + .clipShape(RoundedRectangle(cornerRadius: 10)) + VStack(alignment: .leading) { + Text("Send Me Money Directly") + .fontWeight(.bold) + Text("I have nothing specific to say here!") + .foregroundStyle(.secondary) + .multilineTextAlignment(.leading) + } + Spacer() + Image(systemName: "chevron.forward") + } + .padding(.all, 6) + .background ( + RoundedRectangle(cornerRadius: 8) + .fill(Color.secondary.opacity(0.1)) + ) + } + .buttonStyle(.plain) + } + .frame(maxWidth: .infinity, maxHeight: .infinity) + .toolbar { + Button(action: { + dismiss() + }) { + Image(systemName: "xmark") + } + } + } + .padding(.horizontal, 10) + } +} + +#Preview { + DonationView() +} diff --git a/RIT Dining/VisitingChefs.swift b/RIT Dining/Views/VisitingChefs.swift similarity index 100% rename from RIT Dining/VisitingChefs.swift rename to RIT Dining/Views/VisitingChefs.swift