Added donation view

It seems reasonable to ask for some money here or there, since my Apple Developer Program membership was quite expensive just for this app
This commit is contained in:
Campbell 2025-09-17 22:38:09 -04:00
parent 9d16be646a
commit 2c607553ac
Signed by: NinjaCheetah
GPG Key ID: 39C2500E1778B156
14 changed files with 216 additions and 33 deletions

View File

@ -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;

View File

@ -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()
}

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "kofiLogo.png",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "paypalLogo.png",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -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()
}
}
}

View File

@ -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<V: View>(@ViewBuilder _ block: (Self) -> V) -> V { block(self) }
}

View File

@ -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()
}

View File

@ -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()
}