Skip to content

Instantly share code, notes, and snippets.

@customsoftware
Last active September 28, 2018 12:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save customsoftware/35ce68802cf5882ecda9c18038b4fdfe to your computer and use it in GitHub Desktop.
Save customsoftware/35ce68802cf5882ecda9c18038b4fdfe to your computer and use it in GitHub Desktop.
A Sample of my latest work
//
// NewCheckInComponents.swift
//
// Created by Kenneth Cluff on 8/16/18.
//
import UIKit
extension UILabel {
static func makeCheckInTimeLabel(with caption: String, in containerView: UIView) -> UILabel{
let retValue = UILabel.forAutoLayout()
containerView.addSubview(retValue)
retValue.text = caption
retValue.font = NewCheckInResources.Fonts.lightTitle
retValue.textColor = NewCheckInResources.Colors.checkInStandardText
return retValue
}
static func makeColoredLabel(with caption: String?, and color: UIColor, in containerView: UIView) -> UILabel {
let retValue = UILabel.forAutoLayout()
containerView.addSubview(retValue)
if let caption = caption {
retValue.text = caption
}
retValue.font = NewCheckInResources.Fonts.eventText
retValue.textColor = color
return retValue
}
static func makeTitleLabel(with caption: String?, in containerView: UIView) -> UILabel {
let retValue = UILabel.forAutoLayout()
containerView.addSubview(retValue)
if let caption = caption {
retValue.text = caption
}
retValue.font = NewCheckInResources.Fonts.heavyTitle
retValue.textColor = NewCheckInResources.Colors.checkInStandardText
return retValue
}
static func makeMediumTitleLabel(with caption: String?, in containerView: UIView) -> UILabel {
let retValue = UILabel.forAutoLayout()
containerView.addSubview(retValue)
if let caption = caption {
retValue.text = caption
}
retValue.font = NewCheckInResources.Fonts.mediumTitle
retValue.textColor = NewCheckInResources.Colors.checkInStandardText
return retValue
}
static func makeMeetingInformationLabel(with caption: String, in containerView: UIView) -> UILabel {
let retValue = UILabel.forAutoLayout()
containerView.addSubview(retValue)
retValue.text = caption
retValue.font = NewCheckInResources.Fonts.informationText
retValue.textColor = NewCheckInResources.Colors.checkInStandardText
return retValue
}
static func makeOrganizerInformationLabel(with caption: String?, in containerView: UIView) -> UILabel {
let retValue = UILabel.forAutoLayout()
containerView.addSubview(retValue)
if let caption = caption {
retValue.text = "\(NewCheckInResources.Strings.organizer): \(caption)"
}
retValue.font = NewCheckInResources.Fonts.organizerText
retValue.textColor = NewCheckInResources.Colors.checkInStandardText
return retValue
}
static func makeTimeRemainingToCheckInLabel(in containerView: UIView) -> UILabel {
let retValue = UILabel.forAutoLayout()
containerView.addSubview(retValue)
retValue.font = NewCheckInResources.Fonts.mediumTitle
retValue.textColor = NewCheckInResources.Colors.dark
return retValue
}
}
class ActionButton: UIButton {
static func make(with caption: String, image: UIImage, in containerView: UIView) -> ActionButton {
let retValue = ActionButton.forAutoLayout()
containerView.addSubview(retValue)
retValue.titleLabel?.font = NewCheckInResources.Fonts.buttonText
retValue.setTitle(caption.uppercased(), for: .normal)
retValue.setImage(image, for: .normal)
retValue.layer.cornerRadius = NewCheckInResources.Layout.actionViewCornerRadius
retValue.layer.borderColor = NewCheckInResources.Colors.checkInStandardText.cgColor
retValue.layer.borderWidth = 1.0
return retValue
}
override func layoutSubviews() {
super.layoutSubviews()
if let _ = imageView,
let _ = titleLabel {
imageEdgeInsets = UIEdgeInsets(top: 0, left: -5, bottom: 0, right: 0)
titleEdgeInsets = UIEdgeInsets(top: 0, left: 15, bottom: 0, right: 0)
}
}
}
extension UIImageView {
static func makeLogoImage(in containerView: UIView) -> UIImageView {
let retValue = UIImageView.forAutoLayout()
containerView.addSubview(retValue)
retValue.image = NewCheckInResources.Images.logo
return retValue
}
static func makeCheckedInImage(in containerView: UIView) -> UIImageView {
let retValue = UIImageView.forAutoLayout()
containerView.addSubview(retValue)
retValue.widthAnchor.constraint(equalToConstant: NewCheckInResources.Layout.checkedInImageDimension).isActive = true
retValue.heightAnchor.constraint(equalToConstant: NewCheckInResources.Layout.checkedInImageDimension).isActive = true
retValue.contentMode = .scaleAspectFill
retValue.clipsToBounds = true
retValue.image = NewCheckInResources.Images.checkedIn
return retValue
}
}
extension UIView {
static func makeScoreView(using color: UIColor, in containerView: UIView) -> UIView {
let retValue = UIView.forAutoLayout()
retValue.layer.borderColor = color.cgColor
retValue.layer.borderWidth = 1.0
retValue.widthAnchor.constraint(equalToConstant: NewCheckInResources.Layout.masterScoreWidth).isActive = true
retValue.heightAnchor.constraint(equalToConstant: NewCheckInResources.Layout.masterScoreHeight).isActive = true
containerView.addSubview(retValue)
return retValue
}
}
class TapToCheckInView: UIView {
lazy var checkInCountDown = UILabel.makeTimeRemainingToCheckInLabel(in: self)
private lazy var tapToCheckInPromptLabel = UILabel.makeTitleLabel(with: NewCheckInResources.Strings.tapCheck, in: self)
static func make(in containerView: UIView) -> TapToCheckInView {
let retValue = TapToCheckInView.forAutoLayout()
containerView.addSubview(retValue)
retValue.backgroundColor = NewCheckInResources.Colors.checkInPending
retValue.layer.cornerRadius = NewCheckInResources.Layout.tapViewCornerRadius
retValue.widthAnchor.constraint(equalToConstant: NewCheckInResources.Layout.tapViewWidthConstant).isActive = true
retValue.heightAnchor.constraint(equalToConstant: NewCheckInResources.Layout.tapViewHeightConstant).isActive = true
retValue.tapToCheckInPromptLabel.textColor = NewCheckInResources.Colors.dark
retValue.tapToCheckInPromptLabel.font = NewCheckInResources.Fonts.boldButtonText
retValue.tapToCheckInPromptLabel.text = retValue.tapToCheckInPromptLabel.text?.uppercased()
retValue.tapToCheckInPromptLabel.topAnchor.constraint(equalTo: retValue.topAnchor, constant: NewCheckInResources.Layout.logoMargin).isActive = true
retValue.tapToCheckInPromptLabel.centerXAnchor.constraint(equalTo: retValue.centerXAnchor, constant: NewCheckInResources.Layout.centeredXConstant).isActive = true
retValue.tapToCheckInPromptLabel.heightAnchor.constraint(equalToConstant: NewCheckInResources.Layout.checkedInImageTopMargin).isActive = true
retValue.checkInCountDown.font = NewCheckInResources.Fonts.mediumText
retValue.checkInCountDown.topAnchor.constraint(equalTo: retValue.tapToCheckInPromptLabel.bottomAnchor, constant: NewCheckInResources.Layout.tapViewCornerRadius).isActive = true
retValue.checkInCountDown.centerXAnchor.constraint(equalTo: retValue.centerXAnchor, constant: NewCheckInResources.Layout.centeredXConstant).isActive = true
return retValue
}
}
class ButtonContainerView: UIView {
lazy var minimizeButton = ActionButton.make(with: NewCheckInResources.Strings.minimize, image: NewCheckInResources.Images.minimize, in: self)
lazy var cancelButton = ActionButton.make(with: NewCheckInResources.Strings.cancel, image: NewCheckInResources.Images.cancel, in: self)
lazy var cCancelButtonWidth = makeCancelButtonWidthConstraint()
lazy var cContainerWidth = makeContainerWidthConstraint()
static func make(in containerView: UIView) -> ButtonContainerView {
let retValue = ButtonContainerView.forAutoLayout()
retValue.cContainerWidth.isActive = true
retValue.heightAnchor.constraint(equalToConstant: NewCheckInResources.Layout.actionViewHeight).isActive = true
retValue.minimizeButton.topAnchor.constraint(equalTo: retValue.topAnchor, constant: NewCheckInResources.Layout.zeroMargin).isActive = true
retValue.minimizeButton.leadingAnchor.constraint(equalTo: retValue.leadingAnchor, constant: NewCheckInResources.Layout.zeroMargin).isActive = true
retValue.minimizeButton.widthAnchor.constraint(equalToConstant: 157.0).isActive = true
retValue.minimizeButton.heightAnchor.constraint(equalToConstant: NewCheckInResources.Layout.actionViewHeight).isActive = true
retValue.cancelButton.topAnchor.constraint(equalTo: retValue.topAnchor, constant: NewCheckInResources.Layout.zeroMargin).isActive = true
retValue.cancelButton.leadingAnchor.constraint(equalTo: retValue.minimizeButton.trailingAnchor, constant: NewCheckInResources.Layout.logoMargin).isActive = true
retValue.cancelButton.heightAnchor.constraint(equalToConstant: NewCheckInResources.Layout.actionViewHeight).isActive = true
retValue.cCancelButtonWidth.isActive = true
containerView.addSubview(retValue)
return retValue
}
private func makeCancelButtonWidthConstraint() -> NSLayoutConstraint {
let retValue = NSLayoutConstraint(item: cancelButton, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute , multiplier: 1, constant: 202.0)
return retValue
}
private func makeContainerWidthConstraint() -> NSLayoutConstraint {
let retValue = NSLayoutConstraint(item: self, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute , multiplier: 1, constant: NewCheckInResources.Layout.actionViewWidth)
return retValue
}
}
//
// NewCheckInResources.swift
//
// Created by Kenneth Cluff on 8/16/18.
//
import Foundation
struct NewCheckInResources {
struct Layout {
static let zeroMargin: CGFloat = 0.0
static let topMargin: CGFloat = 24.0
static let timeLabelWidth: CGFloat = 195.0
static let timeLabelHeight: CGFloat = 58.0
static let timelabelTrailing: CGFloat = 21.0
static let leadingMargin: CGFloat = 15.0
static let upNextLabelHeight: CGFloat = 29.0
static let upNextLabelWidth: CGFloat = 224.0
static let titleWidth: CGFloat = 479.0
static let masterMargin: CGFloat = 338.0
static let displayHeight: CGFloat = UIScreen.main.bounds.height
static let logoMargin: CGFloat = 24.0
static let masterScoreTopMargin: CGFloat = 194.0
static let masterScoreWidth: CGFloat = 42.0
static let masterScoreHeight: CGFloat = 2.0
static let centeredXConstant: CGFloat = 0.0
static let tapViewWidthConstant: CGFloat = 480.0
static let tapViewHeightConstant: CGFloat = 144.0
static let tapViewCornerRadius: CGFloat = 8.0
static let tapViewTopMargin: CGFloat = 30.0
static let checkedInImageTopMargin: CGFloat = 48.0
static let checkedInImageDimension: CGFloat = 126.0
static let actionViewWidth: CGFloat = 384.0
static let actionViewHeight: CGFloat = 44.0
static let actionViewCornerRadius: CGFloat = 4.0
static let countDownTimerHeight: CGFloat = 34.0
static let topSeparation: CGFloat = 8.0
static let transparentAlpha: CGFloat = 0.0
static let opaqueAlpha: CGFloat = 1.0
static let animationDuration: Double = 0.33
static let longAnimationDuration: Double = 0.67
}
struct Colors {
static let checkInAvailable = UIColor(hex: "#73D394")
static let checkInPending = UIColor(hex: "#FFB819")
static let checkInBusy = UIColor(hex: "#FD4B46")
static let checkInStandardText = UIColor(hex:"FFFFFF")
static let dark = UIColor(hex: "#232222")
static let gray = UIColor(hex: "#77777A")
}
struct Images {
static let minimize = UIImage(named: "Minimize") ?? UIImage()
static let cancel = UIImage(named: "Trash") ?? UIImage()
static let endEarly = UIImage(named: "ClockEnd") ?? UIImage()
static let bookSpace = UIImage(named: "Book") ?? UIImage()
static let checkedIn = UIImage(named: "Checked In") ?? UIImage()
}
struct Fonts {
static let lightTitle = UIFont(name: "ProximaNovaT-Thin", size: 48.0)
static let mediumTitle = UIFont(name: "ProximaNova-Regular", size: 36.0)
static let heavyTitle = UIFont(name: "ProximaNova-Regular", size: 48.0)
static let eventText = UIFont(name: "ProximaNova-Regular", size: 24.0)
static let mediumText = UIFont(name: "ProximaNova-Medium", size: 28.0)
static let smallMediumText = UIFont(name: "ProximaNova-Medium", size: 18.0)
static let organizerText = UIFont(name: "ProximaNova-Regular", size: 20.0)
static let informationText = UIFont(name: "ProximaNova-Regular", size: 28.0)
static let buttonText = UIFont(name: "ProximaNova-Regular", size: 16.0)
static let boldButtonText = UIFont(name: "ProximaNova-Bold", size: 40.0)
static let smallBoldButtonText = UIFont(name: "ProximaNova-Bold", size: 24.0)
static let lightButtonText = UIFont(name: "ProximaNova-Sbold", size: 28.0)
}
struct Strings {
static let available = NSLocalizedString("event.adhoc.event.available", comment: "Available")
static let awaitingCheckin = NSLocalizedString("event.adhoc.event.awaiting", comment: "Awaiting Check in")
static let bookSpace = NSLocalizedString("event.adhoc.event.book-space", comment: "Book this space")
static let cancel = NSLocalizedString("event.adhoc.event.cancel", comment: "Cancel Event")
static let confirmCancelSchedule = NSLocalizedString("event.adhoc.event.cancel-early", comment: "Cancel Upcoming Event")
static let confirmCancelText = NSLocalizedString("event.adhoc.event.cancel-confirm", comment: "Do you want to cancel the upcoming event?")
static let confirmDoYouWantToEnd = NSLocalizedString("event.adhoc.event.upnext-awaiting", comment: "Do you want to end it?")
static let confirmEndMeetingEarly = NSLocalizedString("event.adhoc.event.end-confirm", comment: "Do you want to end the current event?")
static let dismiss = NSLocalizedString("event.adhoc.event.dismiss", comment: "Dismiss")
static let endCurrent = NSLocalizedString("event.adhoc.event.upnext-awaiting", comment: "End Current Meeting")
static let endCurrentEvent = NSLocalizedString("event.adhoc.event.end-current", comment: "End Current Event")
static let endEvent = NSLocalizedString("event.adhoc.event.end-event", comment: "End event")
static let endMeetingEarly = NSLocalizedString("event.adhoc.event.end-early", comment: "End event early")
static let minimize = NSLocalizedString("event.adhoc.event.minimize", comment: "Minimize")
static let organizer = NSLocalizedString("event.adhoc.event.organizer", comment: "Organizer")
static let rightNow = NSLocalizedString("event.adhoc.event.right-now", comment: "Right now")
static let tapCheck = NSLocalizedString("event.adhoc.event.tap-in", comment: "Tap to check in")
static let timeRemaining = NSLocalizedString("event.adhoc.event.time-remaining", comment: "Time Remaining")
static let unknownTimeRemaining = NSLocalizedString("eventboard.general.unknown-time", comment: "Unknown Time")
static let unknownRoomName = NSLocalizedString("maps.breadcrumb.room.unknown", comment: "Unknown Room")
static let upNextAwaitingCheckIn = NSLocalizedString("event.adhoc.event.upnext-awaiting", comment: "Up next - Awaiting Checkin")
static let upNextCheckedIn = NSLocalizedString("event.adhoc.event.checking-in-to", comment: "Checking in to")
}
}
//
// NewCheckInViewController+Extensions.swift
//
// Created by Kenneth Cluff on 9/14/18.
//
import Foundation
import EBAPI
extension NewCheckInViewController: CheckInDismissable {
func dismissView() {
self.detailView?.cancelTimer()
self.dismiss(animated: true, completion: nil)
}
}
// MARK: - Button actions
@objc extension NewCheckInViewController {
func handleCheckIn(_ gestureRecognizer: UITapGestureRecognizer) {
guard let masterView = masterView,
let detailView = detailView,
gestureRecognizer.view != nil,
gestureRecognizer.state == .ended else { return }
EBCheckInSupportTools.startMeeting(event) { (error) in
if error == nil {
self.event.check(inEvent: true)
self.viewMode = .checkedIn
masterView.transitionFromPreToCheckedIn()
detailView.transitionFromPreToCheckedIn()
UIView.animate(withDuration: NewCheckInResources.Layout.animationDuration, animations: {
self.handleRotation()
self.view.layoutIfNeeded()
}, completion: { (completed) in
self.delegate?.handleCheckIn(with: .successfull)
self.detailView?.transitionFromPreToCheckedInFinal()
})
}
}
}
func handleMinimize() {
delegate?.handleCheckIn(with: .minimize)
dismissView()
}
func handleCancelMeeting() {
let cancelScheduledMeeting = NewCheckInConfirmCancel.make(usingDelegate: self, using: .cancelScheduled)
present(cancelScheduledMeeting, animated: true, completion: nil)
}
func handleBookSpace() {
delegate?.handleCheckIn(with: .bookSpace)
}
func handleEndMeetingEarly() {
let confirmEndEarly = NewCheckInConfirmCancel.make(usingDelegate: self, using: .endEarly)
present(confirmEndEarly, animated: true, completion: nil)
}
}
extension NewCheckInViewController: NewCheckIn {
public func handleCancel(with event: EBEvent) {
EBCheckInSupportTools.handleCancel(with: event) { [weak self] (error) in
if let error = error as NSError?,
error.code == 150 {
self?.reportCancelError()
} else {
guard let device = BSRemoteConfigurationSystem.shared().configuration?.device else { return }
self?.reportCancelAnalytics(for: event, on: device)
}
self?.dismissView()
}
}
public func handleCheckIn(with result: CheckInResult) {
switch result {
case .cancelled:
if let current = EBCalendarSystem.shared().currentEvent,
event.identifier == current.identifier {
EBCheckInSupportTools.endCurrentMeeting(from: self) { [weak self] (error) in
guard error == nil else { return }
self?.dismissView()
}
} else {
EBCheckInSupportTools.cancel(event, didCancelByUserAction: true) { [weak self] (error) in
guard error == nil else { return }
self?.dismissView()
}
}
case .endEarly:
guard let currentEvent = currentEvent else { return }
EBCheckInSupportTools.endCurrentWithoutStatus(from: self) { [weak self] (error) in
defer { self?.dismissView() }
guard error == nil,
let device = BSRemoteConfigurationSystem.shared().configuration?.device else{ return }
self?.reportEndEarlyAnalytics(for: currentEvent, on: device)
self?.delegate?.handleCheckIn(with: .endEarly)
}
case .bookSpace:
delegate?.handleCheckIn(with: .bookSpace)
case .doneWithCheckin:
EBCheckInSupportTools.cancel(event, didCancelByUserAction: false) { [weak self] (error) in
if let error = error as NSError?,
error.code == 150 {
self?.reportCancelError()
} else {
self?.reportAnalytics(on: (self?.event)!, with: "event_checkin_canceled", and: "screen_checkin")
}
self?.dismissView()
}
case .successfull:
EBCheckInSupportTools.startMeeting(event) { [weak self] (error) in
defer { self?.dismissView() }
guard let error = error else {
self?.reportAnalytics(on: (self?.event)!, with: "event_checkin_selected", and: "screen_reservation")
return
}
print(error.localizedDescription)
}
case .minimize:
delegate?.handleCheckIn(with: .minimize)
}
}
private func reportCancelError() {
let actionTitle = NSLocalizedString("eventboard.general.ok", comment: "OK")
let alertTitle = NSLocalizedString("event.error.cancel-recurring.title", comment: "")
let alertMessage = NSLocalizedString("event.error.cancel-recurring.message", comment: "")
let okAction = BSAlertAction(title: actionTitle, style: BSAlertActionStyleCancel, handler: nil)
BSAlertService.alert(withTitle: alertTitle, message: alertMessage, actions: [okAction!])
}
private func reportCancelAnalytics(for event: EBEvent?, on device: BSDevice) {
guard let event = event else { return }
let settings = device.settings
let calendar = settings["calendar"] as? [String: Any]
var calendarId = NSNumber(integerLiteral: 0)
if let calendar = calendar,
let theId = calendar["calendar_identifier"] as? NSNumber {
calendarId = theId
}
let remoteId = event.remoteIdentifier ?? NSNumber(integerLiteral: 0)
let idString = event.identifier ?? ""
let deviceId = device.deviceID ?? ""
let params: [String: Any] = [
"device_id": deviceId,
"event_id": remoteId,
"event_identifier": idString,
"calendar_id": calendarId
]
AnalyticsCenter.sharedCenter.sessionTrack(eventName: "event_checkin_canceled", fromScreen: "screen_checkin", parameters: params)
}
private func reportEndEarlyAnalytics(for currentEvent: EBEvent, on device: BSDevice) {
guard let eventStart = currentEvent.start as NSDate?,
let eventEnd = currentEvent.end as NSDate?,
let now = Date() as NSDate? else { return }
let account = BSAuthenticationSystem.shared().storedAccount
let settings = device.settings
let calendar = settings["calendar"] as? [String: Any]
let start = eventStart.mt_stringFromDateWithISODateTime() ?? ""
let end = eventEnd.mt_stringFromDateWithISODateTime() ?? ""
let today = now.mt_stringFromDateWithISODateTime() ?? ""
let remoteId = currentEvent.remoteIdentifier ?? NSNumber(integerLiteral: 0)
let idString = currentEvent.identifier ?? ""
let deviceId = account?.deviceId ?? ""
let params: [String: Any] = [
"device_id": deviceId,
"event_id": remoteId,
"event_identifier": idString,
"event_start": start,
"event_end": end,
"event_modified_end": today
]
AnalyticsCenter.sharedCenter.sessionTrack(eventName: "event_ended_early", fromScreen: "screen_event_details", parameters: params)
}
private func reportAnalytics(on event: EBEvent, with result: String, and caption: String) {
guard let device = BSRemoteConfigurationSystem.shared().configuration?.device else { return }
let settings = device.settings
let calendar = settings["calendar"] as? [String: Any]
var calendarId = NSNumber(integerLiteral: 0)
if let calendar = calendar,
let theId = calendar["calendar_identifier"] as? NSNumber {
calendarId = theId
}
let remoteId = event.remoteIdentifier ?? NSNumber(integerLiteral: 0)
let idString = event.identifier ?? ""
let deviceId = device.deviceID ?? ""
let params: [String: Any] = [
"device_id": deviceId,
"event_id": remoteId,
"event_identifier": idString,
"calendar_id": calendarId
]
AnalyticsCenter.sharedCenter.sessionTrack(eventName: result, fromScreen: caption, parameters: params)
}
}
//
// NewCheckInViewController.swift
//
// Created by Kenneth Cluff on 8/16/18.
//
import UIKit
import Shared
@objc public class NewCheckInViewController: UIViewController {
lazy var detailView = NewCheckInDetailView.makeDetailView(for: event, with: viewMode!, dismissDelegate: self, and: self, in: view)
lazy var masterView = NewCheckInMasterView.makeMasterView(for: event, with: viewMode!, with: currentEvent, and: self, in: view)
private lazy var cMasterViewWidth = makeMasterWidth()
private lazy var cMasterViewHeight = makeMasterHeight()
private lazy var cDetailViewTop = makeDetailTop()
private lazy var cDetailViewLeading = makeDetailLeading()
private var cancelDate: Date?
private var viewConstraints: [NSLayoutConstraint]? {
guard let detailView = detailView,
let masterView = masterView,
let cDetailViewTop = cDetailViewTop,
let cDetailViewLeading = cDetailViewLeading,
let cMasterViewWidth = cMasterViewWidth,
let cMasterViewHeight = cMasterViewHeight else { return nil }
let masterLeading = NSLayoutConstraint(item: masterView, attribute: .leading, relatedBy: .equal, toItem: view, attribute: .leading, multiplier: 1.0, constant: NewCheckInResources.Layout.zeroMargin)
let masterTop = NSLayoutConstraint(item: masterView, attribute: .top, relatedBy: .equal, toItem: view, attribute: .top, multiplier: 1.0, constant: NewCheckInResources.Layout.zeroMargin)
let detailTrailing = NSLayoutConstraint(item: detailView, attribute: .trailing, relatedBy: .equal, toItem: view, attribute: .trailing, multiplier: 1.0, constant: NewCheckInResources.Layout.zeroMargin)
let detailBottom = NSLayoutConstraint(item: detailView, attribute: .bottom, relatedBy: .equal, toItem: view, attribute: .bottom, multiplier: 1.0, constant: NewCheckInResources.Layout.zeroMargin)
return [
cDetailViewTop,
cDetailViewLeading,
detailTrailing,
detailBottom,
masterTop,
masterLeading,
cMasterViewWidth,
cMasterViewHeight
]
}
var event: EBEvent
var currentEvent: EBEvent?
var viewMode: NewCheckInMode?
weak var delegate: NewCheckIn?
/**
### Overview
This is the entry point for creating and using the NewCheckInViewController. It has four modes of display:
1. Pre-event check in when the room being checked into is available
2. Pre-event check in when the room being checked into is currently occupied
3. When checking into the event is successfull
4. When the room has been checked into and the view is re-appearing after being minimized.
- important: Logic to determine states 1 or 2 is data-driven. If the meeting is currently being used as indicated by EBCalendarSystem.shared().currentEvent not being nil, then it will show the room is busy. Otherwise it will show it is available. If the current event being displayed has the property isCheckedIn == true, then the Checked In or Successful modes will display.
- returns: This returns a NewCheckInViewController object ready to be used in the view controllers present.... method.
*NOTE: This view is designed to be displayed in a modal view control inside the view context of its presenting view controller. By doing so, the view's alpha or transparency is such that the presenting view will be visible under this view. The behavioral trade off is this view's context and ability to change to device rotations will be limited to the ability of the presenting view to respond to device rotation events. If the presenting view will change to orientation changes, this view will too. If not, then it wont.*
Virtually all of the strings and settings used in this view, other than constraint constants are contained in NewCheckInViewResources.swift, in a struct named NewCheckInResources.
- parameters:
- event: This is the event to which users are checking in to...
- delegate: The vew communicates back to the presenting view controller through delegate calls. This value tells you who is to get the callbacks.
*/
@objc public static func make(for event: EBEvent, andDelegate delegate: NewCheckIn?) -> NewCheckInViewController {
let retValue = NewCheckInViewController(with: event)
retValue.view.backgroundColor = .clear
retValue.view.isOpaque = false
retValue.viewMode = retValue.inferMode(with: event)
retValue.configure(with: event, and: delegate)
retValue.setControls()
return retValue
}
private init(with event: EBEvent) {
self.event = event
super.init(nibName: nil, bundle: nil)
}
required public init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
public override func loadView() {
super.loadView()
let baseView = UIView(frame: UIScreen.main.bounds)
view = baseView
}
public override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
handleRotation()
}
@objc public func dismiss() {
detailView?.cancelTimer()
dismiss(animated: true, completion: nil)
}
}
// MARK: - Local API
extension NewCheckInViewController {
func inferMode(with event: EBEvent) -> NewCheckInMode {
var retValue: NewCheckInMode = .preStartCheckInAvailable
if let _ = EBCalendarSystem.shared().currentEvent {
retValue = .preStartCheckInBusy
}
if event.isCheckedIn {
retValue = .checkedIn
}
return retValue
}
func setControls() {
guard let masterView = masterView,
let detailView = detailView,
let viewMode = viewMode else { return }
detailView.actionButtonContainer.cancelButton.addTarget(self, action: #selector(handleCancelMeeting), for: .touchUpInside)
detailView.actionButtonContainer.minimizeButton.addTarget(self, action: #selector(handleMinimize), for: .touchUpInside)
let checkInTapGesture = UITapGestureRecognizer(target: self, action: #selector(handleCheckIn(_:)))
checkInTapGesture.numberOfTouchesRequired = 1
checkInTapGesture.numberOfTapsRequired = 1
switch viewMode {
case .preStartCheckInBusy:
masterView.bookSpaceButton?.addTarget(self, action: #selector(handleEndMeetingEarly), for: .touchUpInside)
detailView.tapToStartMeetingButton.addGestureRecognizer(checkInTapGesture)
case .preStartCheckInAvailable:
masterView.bookSpaceButton?.addTarget(self, action: #selector(handleBookSpace), for: .touchUpInside)
detailView.tapToStartMeetingButton.addGestureRecognizer(checkInTapGesture)
case .successful:
masterView.bookSpaceButton?.addTarget(self, action: #selector(handleEndMeetingEarly), for: .touchUpInside)
case .checkedIn:()
}
}
func configure(with event: EBEvent, and delegate: NewCheckIn?) {
self.event = event
self.delegate = delegate
self.currentEvent = EBCalendarSystem.shared().currentEvent
setViewConstraints()
UIView.animate(withDuration: NewCheckInResources.Layout.longAnimationDuration, animations: {
self.masterView?.alpha = 0.95
self.masterView?.isOpaque = false
self.detailView?.alpha = 0.90
self.detailView?.isOpaque = false
self.view.layoutIfNeeded()
self.handleRotation()
})
}
func handleRotation() {
guard let masterView = masterView,
let detailView = detailView,
let cDetailViewTop = cDetailViewTop,
let cDetailViewLeading = cDetailViewLeading,
let cMasterViewWidth = cMasterViewWidth,
let cMasterViewHeight = cMasterViewHeight else { return }
var newWidth = NewCheckInResources.Layout.zeroMargin
var newHeight = NewCheckInResources.Layout.zeroMargin
var newDetailLeading = NewCheckInResources.Layout.zeroMargin
var newDetailTop = NewCheckInResources.Layout.zeroMargin
if UIDevice.current.orientation.isLandscape {
newWidth = getLayoutConstants()
newHeight = NewCheckInResources.Layout.displayHeight
newDetailLeading = getLayoutConstants()
newDetailTop = NewCheckInResources.Layout.zeroMargin
} else {
newWidth = NewCheckInResources.Layout.displayHeight
newHeight = getLayoutConstants()
newDetailLeading = NewCheckInResources.Layout.zeroMargin
newDetailTop = getLayoutConstants()
}
cDetailViewTop.constant = newDetailTop
cDetailViewLeading.constant = newDetailLeading
cMasterViewWidth.constant = newWidth
cMasterViewHeight.constant = newHeight
masterView.handleRotation()
detailView.handleRotation()
}
func getLayoutConstants() -> CGFloat {
var retValue = CGFloat(0)
if !(viewMode == .checkedIn) {
retValue = NewCheckInResources.Layout.masterMargin
}
return retValue
}
func setViewConstraints() {
guard let viewConstraints = viewConstraints else { return }
NSLayoutConstraint.activate(viewConstraints)
}
func makeMasterHeight() -> NSLayoutConstraint? {
guard let masterView = masterView else { return nil }
return NSLayoutConstraint(item: masterView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: NewCheckInResources.Layout.displayHeight)
}
func makeMasterWidth() -> NSLayoutConstraint? {
guard let masterView = masterView else { return nil }
return NSLayoutConstraint(item: masterView, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: NewCheckInResources.Layout.masterMargin)
}
func makeDetailTop() -> NSLayoutConstraint? {
guard let detailView = detailView else { return nil }
return NSLayoutConstraint(item: detailView, attribute: .top, relatedBy: .equal, toItem: view, attribute: .top, multiplier: 1.0, constant: NewCheckInResources.Layout.masterMargin)
}
func makeDetailLeading() -> NSLayoutConstraint? {
guard let detailView = detailView else { return nil }
return NSLayoutConstraint(item: detailView, attribute: .leading, relatedBy: .equal, toItem: view, attribute: .leading, multiplier: 1.0, constant: NewCheckInResources.Layout.masterMargin)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment