# Project export: Campus Food Truck

This document was generated by HackStack to give an AI agent context about a hackathon project. Sections are labeled with their provenance; content marked as truncated was cut to keep this document small.

## Project metadata

- Hackathon: TreeHacks 2025
- Tagline: Find your favorite food trucks in real-time! Our iOS app helps food truck owners update their location daily, making it easier for students to discover and enjoy great food on the go.
- Devpost: https://devpost.com/software/campus-food-truck
- GitHub: https://github.com/chenxyuhua/campus-foodtruck-finder
- Video: https://player.vimeo.com/video/1057220607?byline=0&portrait=0&title=0#t=
- Team: 1 GitHub contributor(s) — chenxyuhua (6 commits)

## Devpost submission (written by the team)

### Inspiration

Food trucks are a great way for students to enjoy affordable and diverse meals on campus, but they often struggle with visibility due to constantly changing locations. Inspired by the frustration of trying to find our favorite food trucks, we wanted to create a solution that helps both students and food truck owners. By providing a platform for real-time location updates, we aim to bridge the gap between hungry students and mobile vendors.

### What it does

Our iOS app allows food truck owners to update their live location, making it easy for students to find them on an interactive map. Users can search for nearby food trucks, view their menus, and get notified when their favorite trucks are close by. This improves visibility for food truck owners while enhancing convenience for students.

### How we built it

We developed the app using Swift and SwiftUI for the front end, integrating MapKit for real-time location tracking. Firebase was used for backend services, including authentication and database storage. We also implemented push notifications to alert users when a food truck updates its location. The project followed an agile development process, with iterative testing and feedback loops to refine the user experience.

### Challenges we ran into

Implementing real-time location updates while optimizing battery consumption. Ensuring a smooth and responsive user interface with frequent data updates. Designing an intuitive experience that balances functionality and ease of use. Coordinating with food truck owners to gather their input and encourage adoption.

### Accomplishments we're proud of

Successfully integrating live location tracking and real-time updates. Building a clean and user-friendly interface that makes food truck discovery seamless. Implementing push notifications to keep students updated on their favorite trucks. Creating a solution that benefits both food truck owners and students alike.

### What we learned

The importance of user feedback in refining app features and usability. Best practices for handling real-time location data and optimizing performance. How to balance technical challenges with user needs to build a practical solution. The significance of effective communication and collaboration in a development team.

### What's next

We plan to expand the app’s features by adding user reviews, pre-ordering capabilities, and AI-based recommendations based on past preferences. We also aim to partner with more food truck vendors and explore cross-platform development to make the app available on Android.

## README (from the GitHub repository)

No README available.

## Detected evidence (automated analysis)

Indexed codebase: 15 recognized source files, 26 KB.
- Swift (language) — detected in the code

## Codebase structure (from repository index)

### Files (22 of 22)

```
campus-foodtruck-finder.xcodeproj/project.pbxproj
campus-foodtruck-finder.xcodeproj/project.xcworkspace/contents.xcworkspacedata
campus-foodtruck-finder.xcodeproj/xcuserdata/chenyuhua.xcuserdatad/xcschemes/xcschememanagement.plist
campus-foodtruck-finder/Assets.xcassets/AccentColor.colorset/Contents.json
campus-foodtruck-finder/Assets.xcassets/AppIcon.appiconset/Contents.json
campus-foodtruck-finder/Assets.xcassets/Contents.json
campus-foodtruck-finder/campus_foodtruck_finderApp.swift
campus-foodtruck-finder/LocationManager.swift
campus-foodtruck-finder/Models/FoodTruckViewModel.swift
campus-foodtruck-finder/Preview Content/Preview Assets.xcassets/Contents.json
campus-foodtruck-finder/View Models/FoodTruck.swift
campus-foodtruck-finder/Views/ContentView.swift
campus-foodtruck-finder/Views/CreateView.swift
campus-foodtruck-finder/Views/FavoritesView.swift
campus-foodtruck-finder/Views/FoodTruckListView.swift
campus-foodtruck-finder/Views/FoodTruckRow.swift
campus-foodtruck-finder/Views/FoodTruckView.swift
campus-foodtruck-finder/Views/HomeView.swift
campus-foodtruck-finder/Views/SearchView.swift
campus-foodtruck-finderTests/campus_foodtruck_finderTests.swift
campus-foodtruck-finderUITests/campus_foodtruck_finderUITests.swift
campus-foodtruck-finderUITests/campus_foodtruck_finderUITestsLaunchTests.swift
```

### Dependencies

No dependency index available.

### Recent commits (newest first)

- Add logo
- Implement views
- Location manager and view model
- MVVM design
- File structure
- Initial Commit

## Key source files (fetched from GitHub, selected and truncated for size)

### campus-foodtruck-finder/campus_foodtruck_finderApp.swift

```swift
//
//  campus_foodtruck_finderApp.swift
//  campus-foodtruck-finder
//
//  Created by 陈昱桦 on 2/15/25.
//

import SwiftUI

@main
struct FoodTruckFinderApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

```

### campus-foodtruck-finderTests/campus_foodtruck_finderTests.swift

```swift
//
//  campus_foodtruck_finderTests.swift
//  campus-foodtruck-finderTests
//
//  Created by 陈昱桦 on 2/15/25.
//

import Testing
@testable import campus_foodtruck_finder

struct campus_foodtruck_finderTests {

    @Test func example() async throws {
        // Write your test here and use APIs like `#expect(...)` to check expected conditions.
    }

}

```

### campus-foodtruck-finderUITests/campus_foodtruck_finderUITestsLaunchTests.swift

```swift
//
//  campus_foodtruck_finderUITestsLaunchTests.swift
//  campus-foodtruck-finderUITests
//
//  Created by 陈昱桦 on 2/15/25.
//

import XCTest

final class campus_foodtruck_finderUITestsLaunchTests: XCTestCase {

    override class var runsForEachTargetApplicationUIConfiguration: Bool {
        true
    }

    override func setUpWithError() throws {
        continueAfterFailure = false
    }

    @MainActor
    func testLaunch() throws {
        let app = XCUIApplication()
        app.launch()

        // Insert steps here to perform after app launch but before taking a screenshot,
        // such as logging into a test account or navigating somewhere in the app

        let attachment = XCTAttachment(screenshot: app.screenshot())
        attachment.name = "Launch Screen"
        attachment.lifetime = .keepAlways
        add(attachment)
    }
}

```

### campus-foodtruck-finder/LocationManager.swift

```swift
//
//  LocationManager.swift
//  campus-foodtruck-finder
//
//  Created by 陈昱桦 on 2/15/25.
//

import Foundation
import CoreLocation

class LocationManager: NSObject, ObservableObject, CLLocationManagerDelegate {
    private let locationManager = CLLocationManager()
    @Published var location: CLLocation?
    
    override init() {
        super.init()
        self.locationManager.delegate = self
        self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
        self.locationManager.requestWhenInUseAuthorization()
        self.locationManager.startUpdatingLocation()
    }
    
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        location = locations.first
    }
    
    func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
        print("Error getting location: \(error)")
    }
    
    // For location permissions and sharing
    
    func requestLocationPermission() {
        locationManager.requestWhenInUseAuthorization()
        
    }
    
    func getLocation() {
        locationManager.startUpdatingLocation()
    }
    
    func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
        if status == .authorizedWhenInUse || status == .authorizedAlways {
            manager.startUpdatingLocation()
        }
    }
}

```

### campus-foodtruck-finderUITests/campus_foodtruck_finderUITests.swift

```swift
//
//  campus_foodtruck_finderUITests.swift
//  campus-foodtruck-finderUITests
//
//  Created by 陈昱桦 on 2/15/25.
//

import XCTest

final class campus_foodtruck_finderUITests: XCTestCase {

    override func setUpWithError() throws {
        // Put setup code here. This method is called before the invocation of each test method in the class.

        // In UI tests it is usually best to stop immediately when a failure occurs.
        continueAfterFailure = false

        // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
    }

    override func tearDownWithError() throws {
        // Put teardown code here. This method is called after the invocation of each test method in the class.
    }

    @MainActor
    func testExample() throws {
        // UI tests must launch the application that they test.
        let app = XCUIApplication()
        app.launch()

        // Use XCTAssert and related functions to verify your tests produce the correct results.
    }

    @MainActor
    func testLaunchPerformance() throws {
        if #available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 7.0, *) {
            // This measures how long it takes to launch your application.
            measure(metrics: [XCTApplicationLaunchMetric()]) {
                XCUIApplication().launch()
            }
        }
    }
}

```

### campus-foodtruck-finder/Views/ContentView.swift

```swift
//
//  ContentView.swift
//  campus-foodtruck-finder
//
//  Created by 陈昱桦 on 2/15/25.
//

import Foundation
import SwiftUI

struct ContentView: View {
    @ObservedObject var foodTruckViewModel = FoodTruckViewModel()
    @ObservedObject var locationManager = LocationManager()
    
    init() {
        UITabBar.appearance().backgroundColor = UIColor.white
    }
    
    var body: some View {
        TabView {
            HomeView(viewModel: foodTruckViewModel)
                .tabItem {
                    Label("Home", systemImage: "house")
                }
            
            SearchView(viewModel: foodTruckViewModel)
                .tabItem {
                    Label("Search", systemImage: "magnifyingglass")
                }
        
            FavoritesView(viewModel: foodTruckViewModel)
                            .tabItem {
                                Label("Favorites", systemImage: "star.fill")
                            }
            
            CreateView(viewModel: foodTruckViewModel, locationService: locationManager)
                .tabItem {
                    Label("Add", systemImage: "plus.circle.fill")
                }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

```

### campus-foodtruck-finder/Views/FoodTruckRow.swift

```swift
//
//  FoodTruckRow.swift
//  campus-foodtruck-finder
//
//  Created by 陈昱桦 on 2/15/25.
//

import SwiftUI
import CoreLocation

struct FoodTruckRow: View {
    @ObservedObject var viewModel: FoodTruckViewModel
    let truck: FoodTruck
    
    var body: some View {
        HStack {
            VStack(alignment: .leading) {
                Text(truck.name).font(.headline)
            }
            Spacer()
            Image(systemName: truck.isFavorite ? "heart.fill" : "heart")
                .foregroundColor(truck.isFavorite ? .red : .gray)
                .onTapGesture {
                    viewModel.toggleFavorite(truck)
                }
        }
    }
}

struct FoodTruckRow_Previews: PreviewProvider {
    static var previews: some View {
        let viewModel = FoodTruckViewModel()

        viewModel.foodTrucks.append(FoodTruck(
            name: "Tasty Truck",
            location: CLLocation(latitude: 35.6895, longitude: 139.6917),
            hours: "10am - 9pm",
            averagePrice: 8.50,
            category: "Japanese Cuisine",
            isFavorite: true
        ))

        // Return a FoodTruckRow view if a sample truck is available, otherwise return a placeholder Text view.
        return Group {
            if let sampleTruck = viewModel.foodTrucks.first {
                FoodTruckRow(viewModel: viewModel, truck: sampleTruck)
            } else {
                Text("No food trucks available for preview.")
            }
        }
        .previewLayout(.sizeThatFits)
    }
}

```

### campus-foodtruck-finder/Views/SearchView.swift

```swift
//
//  SearchView.swift
//  campus-foodtruck-finder
//
//  Created by 陈昱桦 on 2/15/25.
//

import SwiftUI
import CoreLocation

struct SearchBar: UIViewRepresentable {
    @Binding var text: String

    class Coordinator: NSObject, UISearchBarDelegate {
        @Binding var text: String

        init(text: Binding<String>) {
            _text = text
        }

        func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
            text = searchText
        }
    }

    func makeCoordinator() -> Coordinator {
        return Coordinator(text: $text)
    }

    func makeUIView(context: Context) -> UISearchBar {
        let searchBar = UISearchBar(frame: .zero)
        searchBar.delegate = context.coordinator
        return searchBar
    }

    func updateUIView(_ uiView: UISearchBar, context: Context) {
        uiView.text = text
    }
}

struct SearchView: View {
    @ObservedObject var viewModel: FoodTruckViewModel
    @StateObject private var locationManager = LocationManager()
    @State private var searchText = ""

    var body: some View {
        ScrollView {
            VStack {
                SearchBar(text: $searchText)
                FoodTruckListView(
                    viewModel: viewModel,
                    searchText: $searchText,
                    userLocation: locationManager.location
                )
            }
        }
        .scrollDismissesKeyboard(.interactively)
    }
}

struct SearchView_Previews: PreviewProvider {
    static var previews: some View {
        let viewModel = FoodTruckViewModel()
        SearchView(viewModel: viewModel)
    }
}

```

### campus-foodtruck-finder/Views/FavoritesView.swift

```swift
//
//  FavoritesView.swift
//  campus-foodtruck-finder
//
//  Created by 陈昱桦 on 2/15/25.
//

import SwiftUI
import CoreLocation

struct FavoritesView: View {
    @ObservedObject var viewModel: FoodTruckViewModel

    var body: some View {
        NavigationView {
            List {
                ForEach (viewModel.foodTrucks.filter { $0.isFavorite }) { truck in
                    NavigationLink(destination: FoodTruckView(viewModel: viewModel, foodTruck: truck)) {
                        FoodTruckRow(viewModel: viewModel, truck: truck)
                    }
                }
            }
            .navigationTitle("My Favorites")
        }
        .onAppear {
            viewModel.loadFoodTrucks()
        }
    }
}

struct FavoritesView_Previews: PreviewProvider {
    static var previews: some View {
        // Create an instance of FoodTruckViewModel
        let viewModel = FoodTruckViewModel()
        // Populate it with sample data
        viewModel.foodTrucks = [
            FoodTruck(
                id: UUID(),
                name: "Tasty Truck",
                location: CLLocation(latitude: 35.6895, longitude: 139.6917),
                hours: "10am - 9pm",
                averagePrice: 8.50,
                category: "Japanese Cuisine",
                isFavorite: false
            ),
            FoodTruck(
                id: UUID(),
                name: "Burger Haven",
                location: CLLocation(latitude: 40.7128, longitude: -74.0060),
                hours: "11am - 11pm",
                averagePrice: 10.00,
                category: "Fast Food",
                isFavorite: true
            )
        ]
        
        // Pass the instance, not the type
        return FavoritesView(viewModel: viewModel)
            .environmentObject(viewModel)
    }
}

```

### campus-foodtruck-finder/Models/FoodTruckViewModel.swift

```swift
//
//  FoodTruckViewModel.swift
//  campus-foodtruck-finder
//
//  Created by 陈昱桦 on 2/15/25.
//

import Foundation
import Combine
import MapKit
import CoreLocation

class FoodTruckViewModel: NSObject, ObservableObject, CLLocationManagerDelegate {
    @Published var foodTrucks: [FoodTruck] = []
    @Published var userLocation: CLLocationCoordinate2D?
    private var locationManager = CLLocationManager()
    
    override init() {
        super.init()
        loadFoodTrucks()
        self.locationManager = CLLocationManager()
        locationManager.delegate = self
        locationManager.desiredAccuracy = kCLLocationAccuracyBest
        locationManager.requestWhenInUseAuthorization()
        locationManager.startUpdatingLocation()
    }

    // Adds a new food truck
    func addFoodTruck(_ truck: FoodTruck) {
        foodTrucks.append(truck)
        saveFoodTrucks()
    }
    
    // Deletes a food truck
    func deleteFoodTruck(_ truck: FoodTruck) {
        if let index = foodTrucks.firstIndex(where: { $0.id == truck.id }) {
            foodTrucks.remove(at: index)
            saveFoodTrucks()
        }
    }
    
    // Saves food trucks to persistent storage
    func saveFoodTrucks() {
        if let data = try? JSONEncoder().encode(foodTrucks) {
            UserDefaults.standard.set(data, forKey: "FoodTrucks")
        }
    }

    // Loads food trucks from persistent storage
    func loadFoodTrucks() {
        if let data = UserDefaults.standard.data(forKey: "FoodTrucks"),
           let savedFoodTrucks = try? JSONDecoder().decode([FoodTruck].self, from: data) {
            foodTrucks = savedFoodTrucks
        }
    }
    
    func toggleFavorite(_ truck: FoodTruck) {
        if let index = foodTrucks.firstIndex(where: { $0.id == truck.id }) {
            foodTrucks[index].isFavorite.toggle()
            saveFoodTrucks()
        }
    }
    
}

```

[5 more indexed source files omitted to keep this export small. The full file list is in the Codebase structure section above.]