Giter Club home page Giter Club logo

ios's Introduction

iOS

Build Status

The repo hosts the official iOS app for HackIllinois. If you would like to get involved please reach out to the HackIllinois staff.

Requirements

  1. XCode 13.0+
  2. Swift 5.0+
  3. iOS 13.0+

Installation

git clone https://github.com/HackIllinois/ios.git
cd ios
open Hackillinois.xcodeproj

Contributing

Please contribute using Github Flow. Create a branch, add commits, and open a pull request.

master

Master only hosts versions of the Hackillinois application released to TestFlight or the App Store. Currently 2023.2.0.

dev

Dev hosts a semi-stable version of the next release and all work should be done on branches off dev and commited via PR's.

Support

Please open an issue for support.

License

This project is licensed under the University of Illinois/NCSA License. For a full copy of this license take a look at the LICENSE file.

ios's People

Contributors

aldenlamp avatar alexdrewno avatar anushkasankaran avatar asankaran avatar ashayp22 avatar carters101 avatar darthbatman avatar derek1906 avatar hyosang2 avatar ifisq avatar imathur1 avatar jeffkim2001 avatar kvnloo avatar lasyaneti avatar louisunlimited avatar minhyukpark avatar narendasan avatar nmagerko avatar patle1234 avatar patrickkan avatar rauhul avatar redsn0w422 avatar robertpieta avatar s0phialiu avatar shotaroikeda avatar sujaypat avatar sukipat avatar tommypacker avatar vincentbanguyen avatar zpahuja avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ios's Issues

Fix overly large function bodies

Fix all instances of // swiftlint:disable:next function_body_length.

  • HIAdminEventViewController.didSelectCreateEvent()
    // swiftlint:disable:next function_body_length
    @objc func didSelectCreateEvent() {
    guard let title = titleTextField.text,
    let durationText = durationTextField.text,
    title != "", durationText != "",
    let duration = Int(durationText)
    else { return }
    let message = "Create a new tracked event \"\(title)\" for \(duration) minutes?"
    let confirmAlertController = UIAlertController(title: "Confirm Tracked Event", message: message, preferredStyle: .alert)
    confirmAlertController.addAction(
    UIAlertAction(title: "Yes", style: .default) { _ in
    self.stylizeFor(.currentlyCreatingEvent)
    HITrackingService.create(name: title, duration: duration)
    .onCompletion { result in
    let alertTitle: String
    var alertMessage: String?
    var shouldExitOnCompletion = false
    switch result {
    case .success(let successContainer):
    if let error = successContainer.error {
    alertTitle = error.title
    alertMessage = error.message
    } else {
    alertTitle = "Tracked Event Created"
    shouldExitOnCompletion = true
    }
    case .cancellation:
    alertTitle = "Cancelled"
    case .failure(let error):
    alertTitle = "Error"
    alertMessage = error.localizedDescription
    }
    let alert = UIAlertController(title: alertTitle, message: alertMessage, preferredStyle: .alert)
    alert.addAction(
    UIAlertAction(title: "OK", style: .default) { [weak self] _ in
    if shouldExitOnCompletion {
    self?.navigationController?.popViewController(animated: true)
    }
    }
    )
    DispatchQueue.main.async { [weak self] in
    self?.stylizeFor(.readyToCreateEvent)
    self?.titleTextField.text = ""
    self?.durationTextField.text = ""
    self?.present(alert, animated: true, completion: nil)
    }
    }
    .authorization(HIApplicationStateController.shared.user)
    .perform()
    }
    )
    confirmAlertController.addAction(UIAlertAction(title: "No", style: .cancel, handler: nil))
    self.present(confirmAlertController, animated: true, completion: nil)
    }
  • HIEventDetailViewController.loadView()
    // swiftlint:disable:next function_body_length
    override func loadView() {
    super.loadView()
    let eventDetailContainer = HIView(style: .content)
    eventDetailContainer.translatesAutoresizingMaskIntoConstraints = false
    view.addSubview(eventDetailContainer)
    eventDetailContainer.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 12).isActive = true
    eventDetailContainer.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 12).isActive = true
    eventDetailContainer.bottomAnchor.constraint(lessThanOrEqualTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -12).isActive = true
    eventDetailContainer.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -12).isActive = true
    let upperContainerView = UIView()
    upperContainerView.translatesAutoresizingMaskIntoConstraints = false
    eventDetailContainer.addSubview(upperContainerView)
    upperContainerView.topAnchor.constraint(equalTo: eventDetailContainer.topAnchor).isActive = true
    upperContainerView.leadingAnchor.constraint(equalTo: eventDetailContainer.leadingAnchor).isActive = true
    upperContainerView.trailingAnchor.constraint(equalTo: eventDetailContainer.trailingAnchor).isActive = true
    upperContainerView.heightAnchor.constraint(equalToConstant: 63).isActive = true
    favoritedButton.addTarget(self, action: #selector(didSelectFavoriteButton(_:)), for: .touchUpInside)
    upperContainerView.addSubview(favoritedButton)
    favoritedButton.topAnchor.constraint(equalTo: upperContainerView.topAnchor).isActive = true
    favoritedButton.leadingAnchor.constraint(equalTo: upperContainerView.leadingAnchor).isActive = true
    favoritedButton.bottomAnchor.constraint(equalTo: upperContainerView.bottomAnchor).isActive = true
    favoritedButton.widthAnchor.constraint(equalToConstant: 58).isActive = true
    titleLabel.textColor = HIAppearance.current.primary
    titleLabel.font = UIFont.systemFont(ofSize: 18, weight: .light)
    titleLabel.translatesAutoresizingMaskIntoConstraints = false
    upperContainerView.addSubview(titleLabel)
    titleLabel.leadingAnchor.constraint(equalTo: favoritedButton.trailingAnchor).isActive = true
    titleLabel.trailingAnchor.constraint(equalTo: upperContainerView.trailingAnchor, constant: -8).isActive = true
    titleLabel.centerYAnchor.constraint(equalTo: upperContainerView.centerYAnchor).isActive = true
    descriptionLabel.numberOfLines = 0
    descriptionLabel.textColor = HIAppearance.current.primary
    descriptionLabel.font = UIFont.systemFont(ofSize: 13)
    descriptionLabel.translatesAutoresizingMaskIntoConstraints = false
    eventDetailContainer.addSubview(descriptionLabel)
    descriptionLabel.topAnchor.constraint(equalTo: upperContainerView.bottomAnchor).isActive = true
    descriptionLabel.leadingAnchor.constraint(equalTo: eventDetailContainer.leadingAnchor, constant: 12).isActive = true
    descriptionLabel.trailingAnchor.constraint(equalTo: eventDetailContainer.trailingAnchor, constant: -12).isActive = true
    descriptionLabelHeight = descriptionLabel.heightAnchor.constraint(equalToConstant: 100)
    descriptionLabelHeight.isActive = true
    let tableView = UITableView()
    tableView.backgroundColor = HIAppearance.current.contentBackground
    tableView.translatesAutoresizingMaskIntoConstraints = false
    eventDetailContainer.addSubview(tableView)
    tableView.topAnchor.constraint(equalTo: descriptionLabel.bottomAnchor, constant: 8).isActive = true
    tableView.leadingAnchor.constraint(equalTo: eventDetailContainer.leadingAnchor).isActive = true
    tableView.bottomAnchor.constraint(equalTo: eventDetailContainer.bottomAnchor, constant: -6).isActive = true
    tableView.trailingAnchor.constraint(equalTo: eventDetailContainer.trailingAnchor).isActive = true
    tableViewHeight = tableView.heightAnchor.constraint(equalToConstant: 0)
    tableViewHeight.isActive = true
    self.tableView = tableView
    }
  • HIUserPassLoginViewController.loadView()
    // swiftlint:disable:next function_body_length
    override func loadView() {
    super.loadView()
    let backButton = HIButton(style: .icon(image: #imageLiteral(resourceName: "BackButton")))
    backButton.addTarget(self, action: #selector(didSelectBack), for: .touchUpInside)
    view.addSubview(backButton)
    backButton.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
    backButton.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor).isActive = true
    backButton.widthAnchor.constraint(equalToConstant: 67).isActive = true
    backButton.heightAnchor.constraint(equalToConstant: 44).isActive = true
    let logInLabel = HILabel(style: .loginHeader)
    logInLabel.text = "LOG IN"
    view.addSubview(logInLabel)
    logInLabel.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 54).isActive = true
    logInLabel.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 29).isActive = true
    logInLabel.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -29).isActive = true
    logInLabel.heightAnchor.constraint(equalToConstant: 22).isActive = true
    containerView.translatesAutoresizingMaskIntoConstraints = false
    view.addSubview(containerView)
    containerView.topAnchor.constraint(equalTo: logInLabel.bottomAnchor, constant: 23).isActive = true
    containerView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 30).isActive = true
    containerView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -30).isActive = true
    containerView.heightAnchor.constraint(equalToConstant: 89).isActive = true
    containerView.addSubview(emailTextField)
    emailTextField.topAnchor.constraint(equalTo: containerView.topAnchor, constant: 0).isActive = true
    emailTextField.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: 0).isActive = true
    emailTextField.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: 0).isActive = true
    emailTextField.heightAnchor.constraint(equalToConstant: 44).isActive = true
    let separatorView = HIView(style: .separator)
    containerView.addSubview(separatorView)
    separatorView.topAnchor.constraint(equalTo: emailTextField.bottomAnchor).isActive = true
    separatorView.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: 0).isActive = true
    separatorView.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: 0).isActive = true
    containerView.addSubview(passwordTextField)
    passwordTextField.topAnchor.constraint(equalTo: separatorView.bottomAnchor).isActive = true
    passwordTextField.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: 0).isActive = true
    passwordTextField.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: 0).isActive = true
    passwordTextField.heightAnchor.constraint(equalToConstant: 44).isActive = true
    view.addSubview(signInButton)
    signInButton.topAnchor.constraint(equalTo: containerView.bottomAnchor, constant: 71).isActive = true
    signInButton.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 12).isActive = true
    signInButton.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -12).isActive = true
    signInButton.heightAnchor.constraint(equalToConstant: 50).isActive = true
    }
  • HIEventDataSource.refresh(completion:)
    // swiftlint:disable:next function_body_length
    static func refresh(completion: (() -> Void)? = nil) {
    guard !isRefreshing else {
    completion?()
    return
    }
    isRefreshing = true
    HIEventService.getAllLocations()
    .onCompletion { result in
    if case let .success(containedLocations) = result {
    print("GET::LOCATIONS::SUCCESS")
    HIEventService.getAllEvents()
    .onCompletion { result in
    if case let .success(containedEvents) = result {
    print("GET::EVENTS::SUCCESS")
    HIEventService.getAllFavorites()
    .onCompletion { result in
    if case let .success(containedFavorites) = result {
    print("GET::FAVORITES::SUCCESS")
    var updatedEvents = [HIAPIEvent]()
    containedEvents.data.forEach { event in
    var event = event
    event.favorite = containedFavorites.data.map { $0.eventId }.contains(event.id)
    updatedEvents.append(event)
    }
    DispatchQueue.main.sync {
    do {
    let ctx = CoreDataController.shared.persistentContainer.viewContext
    try? ctx.fetch(locationsFetchRequest).forEach {
    ctx.delete($0)
    }
    try? ctx.fetch(eventsFetchRequest).forEach {
    ctx.delete($0)
    }
    var locations = [Location]()
    containedLocations.data.forEach { location in
    locations.append( Location(context: ctx, location: location) )
    }
    var events = [Event]()
    updatedEvents.forEach { event in
    let eventLocationIds = event.locations.map { Int16($0.locationId) }
    let eventLocations = locations.filter { eventLocationIds.contains($0.id) }
    events.append( Event(context: ctx, event: event, locations: NSSet(array: eventLocations)) )
    }
    HILocalNotificationController.shared.scheduleNotifications(for: events)
    try ctx.save()
    } catch { }
    }
    }
    completion?()
    isRefreshing = false
    }
    .authorization(HIApplicationStateController.shared.user)
    .perform()
    } else {
    completion?()
    isRefreshing = false
    }
    }
    .authorization(HIApplicationStateController.shared.user)
    .perform()
    } else {
    completion?()
    isRefreshing = false
    }
    }
    .authorization(HIApplicationStateController.shared.user)
    .perform()
    }
    }

Fix menu layout bug

Closing and reopening the app with menu open causes hamburger icon to jump to top left corner. Likely a safe area bug.

Podfile is broken

$ pod install
Analyzing dependencies
Pre-downloading: `JWTDecode` from `https://github.com/auth0/JWTDecode.swift.git`, branch `feature-swift-3`
[!] The `JWTDecode` pod failed to validate due to 1 error.
[!] The validator for Swift projects uses Swift 3.0 by default, if you are using a different version of swift you can use a `.swift-version` file to set the version for your Pod. For example to use Swift 2.3, run:
    `echo "2.3" > .swift-version`:
    - ERROR | version: A version is required.

Add travis check for file headers

We should add a ci script to check that all swift files begin with a header in the format below. The script should live under .ci/.

//
//  <FILE_NAME>.swift
//  HackIllinois
//
//  Created by <FIRST> <LAST> on ##/##/##.
//  Copyright © <YEAR> HackIllinois. All rights reserved.
//  This file is part of the Hackillinois iOS App.
//  The Hackillinois iOS App is open source software, released under the University of
//  Illinois/NCSA Open Source License. You should have received a copy of
//  this license in a file with the distribution.
//

Create AnnouncementAdminViewController

Need to make an AnnouncementAdminViewController so staff can create/push announcements to the app as needed. Should essentially look like a form.

AnnouncementAdminViewController should appear in modals.storyboard

Update OAuth for API

API flow for OAuth changed. iOS HTTP requests need to be updated to allow for proper OAuth login.

QRCode generation

We should generate a QR code when user first logs in.
The code should contain the following data: hackillinois://qrcode/user?id=&identifier=

Once this first step is done, we also introduce a two level image cache for future proofing.
This cache manager will use an in memory NSCache as well as a disk cache.

App Release Checklist

Checklist

Cosmetics

  • Day color palette
  • Night color palette
  • Images
  • Lottie animations
  • No auto-layout warnings

Functionality

Persistent Data

  • Keychain stores login data
  • Purge persistent data on logout
  • Properly update events
  • Properly update announcements

Login/Logout

  • Login
  • Logout
  • Keychain auto-login

Home View

  • Countdown times
  • Upcoming Events
  • Happening Now Events

Schedule

  • Properly update tableview on tab change
  • Pull to refresh
  • Favorite/Unfavorite
  • Locations appear alphabetically
  • Cells push to detail view

TODO: finish list

Admin event editing

Functionality for admins to swipe left on event to delete and swipe right to edit

Auto Layout issue on HIScheduleViewController

Constraints on this view are broken, end up hiding the segmented control at the top of the view. Potentially due to using the new swift build system?

Debug output:

(
    "<NSLayoutConstraint:0x60c00008bae0 HackIllinois.HISegmentedControl:0x7f7ffe011380.height == 34   (active)>",
    "<NSLayoutConstraint:0x600000283e80 HackIllinois.HISegmentedControl:0x7f7ffe011380.top == UILayoutGuide:0x6000001bb120'UIViewSafeAreaLayoutGuide'.top   (active)>",
    "<NSLayoutConstraint:0x600000284100 V:[HackIllinois.HISegmentedControl:0x7f7ffe011380]-(0)-[UITableView:0x7f7ffd83dc00]   (active)>",
    "<NSAutoresizingMaskLayoutConstraint:0x608000094870 h=--- v=--- 'UIView-Encapsulated-Layout-Top' UIView:0x7f7ffe0111a0.minY == 0   (active)>",
    "<NSLayoutConstraint:0x600000281cc0 'UIViewSafeAreaLayoutGuide-top' V:|-(0)-[UILayoutGuide:0x6000001bb120'UIViewSafeAreaLayoutGuide']   (active, names: '|':UIView:0x7f7ffe0111a0 )>"
)

Use Why The Failure, Auto Layout? for human readable description.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.