# Project export: Lounge Locate

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: CruzHacks 2024
- Tagline: Lounge Locate is an iOS application that displays UCSC lounge, café, and library locations on a map, allowing students to easily visualize and reach nearby study spots on campus.
- Devpost: https://devpost.com/software/lounge-locate
- GitHub: https://github.com/ShivaRavinutala/Lounge_Locate
- Video: https://www.youtube.com/embed/MnwUHjb5xzI?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Team: 1 GitHub contributor(s) — ShivaRavinutala (2 commits)

## Devpost submission (written by the team)

### Inspiration

With a large group of friends like ours, you’ll almost always find us together in a lounge, laughing, talking, or sometimes working silently. However, the events it takes to get there often resemble a very different experience. 10 people manage to agree on a meeting time and location, only to find that that lounge is closed. The group trudges back to try a different location, only to find a place that’s extremely loud and packed! Finally, everyone heads to their last known location, where they can finally settle down and begin their work. With so much trial and error in our process, a lot of time is wasted in finding a space with the right environment for our activities.

### What it does

With this in mind, we created Lounge Locate, an app that displays lounges, cafes, and libraries in UCSC, with further pop-up information about timings, rush hours, etc. The functionality is simple: click on a lounge location to identify the environment at the given time and see what facilities are available.

### How we built it

Using an array of different lounge locations stored in a local .json file, we were able to create custom pins at every lounge’s coordinates that call a pop up function to display information about the lounge when pressed. The pins are designed with an overlaid button that utilizes a state variable integer to access the correct array element and present the pop up view with the right name, description and images. With this design, we were able to create one pop up template that could easily replace the presented information.

### Challenges we ran into

As beginners, we faced many challenges with implementing our idea for the app while learning the language and UI at the same time. One of our biggest challenges was overlaying the custom buttons onto the Apple Maps pin and having it present the pop up view with the correct information. While we were able to conceptually identify multiple ways to accomplish this task, it took extensive research to actually implement onto our app. At first, we considered the Apple Maps pins and its selected feature along with a .tag(int) attribute. Our idea was that the integer from .tag() could be used to access the correct element of the array, and the isSelected feature would present the pop up view. After extensive research of the .tag() documentation, we realized this method would not be possible. Next, we considered overlaying a button over the pin using ZStack() with a return value integer of the array element we wanted to access. We realized quickly that returning a value through the button meant that the pop up action would not actually occur, as returning a value terminates the function. We were on the right track to our final implementation. After thorough research, we identified a concept called a state variable, which was an integer value we could assign to the button that could be accessed throughout the program once the button was clicked. This variable was what we passed through as our parameter, and was able to call the correct information per button clicked.

### Accomplishments we're proud of

We are very proud of our perseverance in overcoming obstacles throughout our project and maintaining our initial idea and implementation. While we had a conceptual idea of how we wanted our project to look and function, it took tremendous effort to program our desired features while simultaneously learning the language, which we commend ourselves for accomplishing. One success that was a pivotal turning point in our project was learning how to overlay a button onto the Apple Maps at a specific coordinate and implement the state variable as a parameter to access the array elements. We are very proud of ourselves for working hard to stay consistent with our initial vision for the app we wanted to build.

### What we learned

On the technical side, we learned how to build an Apple Maps screen fixed to the UC Santa Cruz College region. We learned to utilize an array of Landmark Objects with inputted coordinates, and how to access its attributes across multiple files through the Swift programming language. We also learned how to overlay pins, buttons, and pop up files on the Apple Maps feature in Swift to display custom buttons pinned to exact coordinates that follow through with a pop up that takes in arguments from a state variable integer assigned to each button. This experience has taught us what it is like to build a fully functional app within a high-stress working environment and a 48 hour time constraint. This hackathon has revealed many of our strengths, which we utilized throughout the event to overcome multiple challenges and prepare well for a successful submission.

### What's next

Our vision for Lounge Locate is to include more personalized features: set the map to pinpoint and follow the user’s location, allow users to create logins, pick favorite lounges, and filter their view based on their preferences. With the implementation of individual logins, we aim to integrate group coordination through the app, where multiple people can coordinate with nearest or favorite lounge recommendation features.

## README (from the GitHub repository)

# Lounge_Locate
A lounge locating app that shows the lounges that are available in UCSC


## Detected evidence (automated analysis)

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

## Codebase structure (from repository index)

### Files (44 of 44)

```
CruzHacks.xcodeproj/project.pbxproj
CruzHacks.xcodeproj/project.xcworkspace/contents.xcworkspacedata
CruzHacks.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
CruzHacks.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
CruzHacks.xcodeproj/project.xcworkspace/xcuserdata/shiva.xcuserdatad/UserInterfaceState.xcuserstate
CruzHacks.xcodeproj/xcuserdata/nehaashwin.xcuserdatad/xcschemes/xcschememanagement.plist
CruzHacks.xcodeproj/xcuserdata/shiva.xcuserdatad/xcschemes/xcschememanagement.plist
CruzHacks/Assets.xcassets/AccentColor.colorset/Contents.json
CruzHacks/Assets.xcassets/AppIcon.appiconset/Contents.json
CruzHacks/Assets.xcassets/california-santa-cruz-perk-coffee-bar-at-physical-sciences.imageset/Contents.json
CruzHacks/Assets.xcassets/Contents.json
CruzHacks/Assets.xcassets/crownlibrary.imageset/Contents.json
CruzHacks/Assets.xcassets/firesidelounge.imageset/Contents.json
CruzHacks/Assets.xcassets/kresge-study-center.imageset/Contents.json
CruzHacks/Assets.xcassets/Namaste.imageset/Contents.json
CruzHacks/Assets.xcassets/pagesmith.imageset/Contents.json
CruzHacks/Assets.xcassets/perks-at-baskin.imageset/Contents.json
CruzHacks/Assets.xcassets/perks-at-earth-and-marine.imageset/Contents.json
CruzHacks/Assets.xcassets/pngtree-compass-needle-image_2239468-removebg-preview.imageset/Contents.json
CruzHacks/Assets.xcassets/porter-hitchcock-lounge.imageset/Contents.json
CruzHacks/Assets.xcassets/reclounge.imageset/Contents.json
CruzHacks/Assets.xcassets/redroom.imageset/Contents.json
CruzHacks/Assets.xcassets/socsci1-pc.imageset/Contents.json
CruzHacks/Assets.xcassets/standard.imageset/Contents.json
CruzHacks/Assets.xcassets/stevenson library.imageset/Contents.json
CruzHacks/Assets.xcassets/terry_freitas_pic2a.imageset/Contents.json
CruzHacks/CruzHacks.swift
CruzHacks/Model/Landmark.swift
CruzHacks/Model/ModelData.swift
CruzHacks/PopUpView.swift
CruzHacks/Preview Content/Preview Assets.xcassets/Contents.json
CruzHacks/Resources/landmarkData.json
CruzHacks/SheetManager.swift
CruzHacks/Views/CircleImage.swift
CruzHacks/Views/ContentView.swift
CruzHacks/Views/LandmarkDetail.swift
CruzHacks/Views/LandmarkList.swift
CruzHacks/Views/LandmarkRow.swift
CruzHacks/Views/Launch Screen.storyboard
CruzHacks/Views/MapView.swift
CruzHacksTests/CruzHacksTests.swift
CruzHacksUITests/CruzHacksUITests.swift
CruzHacksUITests/CruzHacksUITestsLaunchTests.swift
README.md
```

### Dependencies

No dependency index available.

### Recent commits (newest first)

- Uploaded final files of project
- Initial commit

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

### CruzHacks/CruzHacks.swift

```swift
//
//  CruzHacksApp.swift
//  CruzHacks
//
//  Created by Neha Ashwin on 1/19/24.
//

import SwiftUI

@main
struct CruzHacksApp: App {
    
    @StateObject var sheetManager = SheetManager()
    
    var body: some Scene {
        WindowGroup {
            MapView()
                .environmentObject(sheetManager)
        }
    }
}

```

### CruzHacks/SheetManager.swift

```swift
//
//  SheetManager.swift
//  CruzHacks
//
//  Created by Neha Ashwin on 1/20/24.
//

import Foundation

final class SheetManager: ObservableObject {
    enum Action {
        case na
        case present
        case dismiss
    }
    
    @Published private(set) var action: Action = .na
    
    func present() {
        guard !action.isPresented else { return }
        self.action = .present
    }
    
    func dismiss() {
        self.action = .dismiss
    }
    
}

extension SheetManager.Action {
    var isPresented: Bool { self == .present }
}

```

### CruzHacksUITests/CruzHacksUITestsLaunchTests.swift

```swift
//
//  CruzHacksUITestsLaunchTests.swift
//  CruzHacksUITests
//
//  Created by Neha Ashwin on 1/19/24.
//

import XCTest

final class CruzHacksUITestsLaunchTests: XCTestCase {

    override class var runsForEachTargetApplicationUIConfiguration: Bool {
        true
    }

    override func setUpWithError() throws {
        continueAfterFailure = false
    }

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

```

### CruzHacksTests/CruzHacksTests.swift

```swift
//
//  CruzHacksTests.swift
//  CruzHacksTests
//
//  Created by Neha Ashwin on 1/19/24.
//

import XCTest
@testable import CruzHacks

final class CruzHacksTests: XCTestCase {

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

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

    func testExample() throws {
        // This is an example of a functional test case.
        // Use XCTAssert and related functions to verify your tests produce the correct results.
        // Any test you write for XCTest can be annotated as throws and async.
        // Mark your test throws to produce an unexpected failure when your test encounters an uncaught error.
        // Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions afterwards.
    }

    func testPerformanceExample() throws {
        // This is an example of a performance test case.
        self.measure {
            // Put the code you want to measure the time of here.
        }
    }

}

```

### CruzHacksUITests/CruzHacksUITests.swift

```swift
//
//  CruzHacksUITests.swift
//  CruzHacksUITests
//
//  Created by Neha Ashwin on 1/19/24.
//

import XCTest

final class CruzHacksUITests: 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.
    }

    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.
    }

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

```

### CruzHacks/PopUpView.swift

```swift
//
//  PopUpView.swift
//  CruzHacks
//
//  Created by Neha Ashwin on 1/20/24.
//Add more background lining + shadow
//

import SwiftUI

struct PopUpView: View {
    
    var landmark: Landmark
    let didClose: () -> Void
    
    var body: some View {
        VStack(spacing: .zero) {
            icon
            title
            content
        }
        .frame(width: 310, height: 400)
        .padding(.horizontal, 24)
        .padding(.vertical, 40)
        .multilineTextAlignment(.center)
        .background(background)
        .overlay(alignment: .topTrailing) {
            close
        }
        
    }
}

struct PopUpView_Previews: PreviewProvider {
    static var previews: some View {
        PopUpView(landmark: landmarks[0]) {}
            .padding()
            .shadow(radius: 7)
            .background(.blue)
            .previewLayout(.sizeThatFits)
            
    }
}

private extension PopUpView {
    var background: some View {
        RoundedCorners(color: .white, tl: 10, tr: 10, bl: 10, br: 10)
            .shadow(color: .black.opacity(0.2), radius: 3)
    }
}

private extension PopUpView {
    
    var close: some View {
        Button {
            didClose()
        } label: {
            Image(systemName: "xmark")
                .symbolVariant(.circle.fill)
                .font(
                    .system(size: 35,
                            weight: .bold,
                            design: .rounded)
                )
                .foregroundStyle(.gray.opacity(0.4))
                .padding(8)
        }
    }
    
    var icon: some View {
        
        landmark.image
            .frame(width: 200, height: 200)
            .clipShape(/*@START_MENU_TOKEN@*/Circle()/*@END_MENU_TOKEN@*/)
            .overlay {
                Circle().stroke(.white, lineWidth: 4)
            }
            .shadow(radius: 7)
    }
    
    var title: some View {
        Text(landmark.name)
            .font(
                .system(size: 30,
                        weight: .bold,
                        design: .rounded)
            )
            .padding()
            .fixedSize()
    }
    
    var content: some View {
        HStack {
            Text(landmark.description)
                .font(.callout)
                .foregroundColor(.black.opacity(0.8))
                .fixedSize(horizontal: false, vertical: /*@START_MENU_TOKEN@*/true/*@END_MENU_TOKEN@*/)
            //Spacer()
        }
        
    }
}

struct RoundedCorners: View {
    var color: Color = .blue
    var tl: CGFloat = 0.0
    var tr: CGFloat = 0.0
    var bl: CGFloat = 0.0
    var br: CGFloat = 0.0
    
    var body: some View {
        GeometryReader { geometry in
            Path { path in
                
                let w = geometry.size.width
                let h = geometry.size.height

                // Make sure we do not exceed the size of the rectangle
                let tr = min(min(self.tr, h/2), w/2)
                let tl = min(min(self.tl, h/2), w/2)
                let bl = min(min(self.bl, h/2), w/2)
                let br = min(min(self.br, h/2), w/2)
                
                path.move(to: CGPoint(x: w / 2.0, y: 0))
                path.addLine(to: CGPoint(x: w - tr, y: 0))
                path.addArc(center: CGPoint(x: w - tr, y: tr), radius: tr, startAngle: Angle(degrees: -90), endAngle: Angle(degrees: 0), clockwise: false)
                path.addLine(to: CGPoint(x: w, y: h - br))
                path.addArc(center: CGPoint(x: w - br, y: h - br), radius: br, startAngle: Angle(degrees: 0), endAngle: Angle(degrees: 90), clockwise: false)
                path.addLine(to: CGPoint(x: bl, y: h))
                path.addArc(center: CGPoint(x: bl, y: h - bl), radius: bl, startAngle: Angle(degrees: 90), endAngle: Angle(degrees: 180), clockwise: false)
                path.addLine(to: CGPoint(x: 0, y: tl))
                path.addArc(center: CGPoint(x: tl, y: tl), radius: tl, startAngle: Angle(degrees: 180), endAngle: Angle(degrees: 270), clockwise: false)
                path.closeSubpath()
            }
            .fill(self.color)
        }
    }
}

```

### CruzHacks/Views/ContentView.swift

```swift
//
//  ContentView.swift
//  CruzHacks
//
//  Created by Neha Ashwin on 1/19/24.
//

import SwiftUI

struct ContentView: View {
    var body: some View {

       LandmarkList()
    }
}

#Preview {
    ContentView()
}

```

### CruzHacks/Views/LandmarkList.swift

```swift
//
//  LandmarkList.swift
//  CruzHacks
//
//  Created by Neha Ashwin on 1/20/24.
//

import SwiftUI

struct LandmarkList: View {
    var body: some View {
        NavigationSplitView {
            List(landmarks) { landmark in
                NavigationLink {
                    LandmarkDetail()
                } label: {
                    LandmarkRow(landmark: landmark)
                }
            }
            .navigationTitle("Lounges")
        } detail: {
            Text("Select a Lounge")
        }
        
    }
}

#Preview {
    LandmarkList()
}

```

### CruzHacks/Views/LandmarkRow.swift

```swift
//
//  LandmarkRow.swift
//  CruzHacks
//
//  Created by Neha Ashwin on 1/20/24.
//

import SwiftUI

struct LandmarkRow: View {
    var landmark: Landmark
    
    var body: some View {
        HStack{
            landmark.image
                .resizable()
                .frame(width: 50, height: 50)
            Text(landmark.name)
            
            Spacer()
        }
        
    }
}

#Preview {
    Group {
        LandmarkRow(landmark: landmarks[0])
        LandmarkRow(landmark: landmarks[1])
    }
    
}

/*#Preview("Salmon") {
    LandmarkRow(landmark: landmarks[1])
}*/

```

### CruzHacks/Model/ModelData.swift

```swift
//
//  ModelData.swift
//  CruzHacks
//
//  Created by Neha Ashwin on 1/20/24.
//

import Foundation

var landmarks: [Landmark] = load(filename: "landmarkData.json")


func load<T: Decodable>(  filename: String) -> T{
    let data: Data
    
    guard let file = Bundle.main.url(forResource: filename, withExtension: nil)
    else {
        fatalError("Couldn't find \(filename) in main bundle.")
    }
    
    do{
        data = try Data(contentsOf: file)
    } catch {
        fatalError("Couldn't find \(filename) in main bundle.")
    }
    
    do{
        let decoder = JSONDecoder()
        return try decoder.decode(T.self, from: data)
    } catch {
        fatalError("Couldn't parse \(filename) as \(T.self):\n\(error)")
    }
}

```

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