VMF_MainViewController
class VMF_MainViewController : VMF_BaseViewController, VMF_MasterTableControllerProtocol
extension VMF_MainViewController: UIPageViewControllerDataSource
extension VMF_MainViewController: UIPageViewControllerDelegate
extension VMF_MainViewController: UIPickerViewDataSource
extension VMF_MainViewController: UIPickerViewDelegate
This is the main view controller for the weekday/time selector tab.
QUICK OVERVIEW
The way that the data is set up, we have “day indexes (1-7), and "time slots” (varies, per day).
All times are mapped to the user’s local timezone, regardless of the start time in the meeting’s “native” timezone.
The instance of this class will have a VMF_DayTimeSearchPageViewController
embedded (also the VMF_AttendanceViewController
class, but that one disables the page view controller), which allows the user to swipe-select pages of meetings.
DAY INDEXES
These represent 0 (In Progress), 1 (Sunday), through 7 (Saturday), or 8 (Search Mode).
Mode 0 (In Progress)
In this mode, there is no “time index,” and the screen displays all meetings that are in progress, regardless of when they started.
Mode 1 -> 7
If the day index is 1 -> 7, the screen displays whatever time index, within that day, is selected.
The day index is stored in Sunday -> Saturday (the database native scheme), but are mapped to the local week, upon display.
Mode 8 (Search)
In this mode, the day index and time index are irrelevant. All possible meetings are displayed, then are filtered, “live,” as text is entered into the text entry field.
TIME INDEXES
Each day has “time slots.” These are groupings of times, where meetings start (1 or more). Each “time slot” is a separate group of meetings that all begin at the same time.
In regular weekdays (day index 1 -> 7), only one “time slot” is shown at a time. Only the meetings that begin at the same time are shown.
If possible, the user’s currently selected time index is honored, and we try to match the time, when changing selected days. It is also preserved, when entering Mode 0 or Mode 8.
SELECTING FOR ATTENDANCE
It is possible for a user to indicate that they attend a meeting, by double-tapping on a meeting in the list, or by selecting “I Attend,” in the meeting inspector screen.
You can bring in a separate screen, that contains only the meetings that you attend. This is accessed from the chackmark bar button item, in the upper right.
-
The segue ID of our open attendance.
Declaration
Swift
static let openAttendanceSegueID: String
-
The image that we use for search mode.
Declaration
Swift
static let searchImage: UIImage?
-
The image to use, when attendance is selected.
Declaration
Swift
static let checkedImage: UIImage?
-
The image to use, when we do not attend.
Declaration
Swift
static let uncheckedImage: UIImage?
-
The color of the “mercury” in our “thermometer.”
Declaration
Swift
static let mercuryColor: UIColor
-
The font for the “I Attend” button.
Declaration
Swift
static let barButtonLabelFont: UIFont
-
The width of each of the components of our direct picker view.
Declaration
Swift
static let pickerViewComponentWidthInDisplayUnits: CGFloat
-
The container view needs to be wider than this, to show short (as opposed to “very” short) weekdays.
Declaration
Swift
static let shortWidthThreshold: CGFloat
-
The container view needs to be wider than this, to show full (as opposed to short) weekdays.
Declaration
Swift
static let fullWidthThreshold: CGFloat
-
This is used to restore the bottom of the stack view, when the keyboard is hidden.
Declaration
Swift
var atRestConstant: CGFloat
-
This is used during the long-press slide. It holds the previous location of the gesture. We use it to determine if the finger has moved.
Declaration
Swift
var oldLocation: CGFloat
-
This holds the last time of the selected page. We use this to set the time, when directly navigating away from Now.
Declaration
Swift
var lastTime: Int
-
This tracks the current embedded table controller.
Declaration
Swift
var tableDisplayController: VMF_EmbeddedTableControllerProtocol?
-
This is our page view controller.
Declaration
Swift
weak var pageViewController: VMF_DayTimeSearchPageViewController?
-
This is set to true, if we were (past tense) in name search mode.
Declaration
Swift
var wasNameSearchMode: Bool
-
Storage for our search meeting source
Declaration
Swift
var searchMeetings: [MeetingInstance]
-
This has the “mostly organized” meeting data.
The meetings are organized in ascending local time, arranged by weekday, with [0] being Sunday.
Declaration
Swift
var organizedMeetings: [[MeetingInstance]]
-
This is set to true, if we are in name search mode.
Declaration
Swift
var isNameSearchMode: Bool { get set }
-
True, if this is the direct weekday/time selection mode (PickerView displayed).
Declaration
Swift
var isDirectSelectionMode: Bool { get set }
-
Contains the search text filter. Only relevant, if in Name Search Mode.
Declaration
Swift
var searchText: String { get set }
-
This is set to true, if the “throbber” is shown (hiding everything else).
Declaration
Swift
var isThrobbing: Bool { get set }
-
The bar button item that brings in the Settings Screen.
Declaration
Swift
@IBOutlet weak var settingsBarButtonItem: UIBarButtonItem?
-
The bar button item that brings in the My Attendance Screen.
Declaration
Swift
@IBOutlet weak var myAttendanceBarButtonItem: UIBarButtonItem?
-
The segmented switch that controls the mode.
Declaration
Swift
@IBOutlet weak var weekdayModeSelectorSegmentedSwitch: UISegmentedControl?
-
The embedded table controller container view. This hosts an instance of
VMF_DayTimeSearchPageViewController
.Declaration
Swift
@IBOutlet weak var tableContainerView: UIView?
-
This contains the search items.
Declaration
Swift
@IBOutlet weak var searchItemsContainerView: UIStackView?
-
The text field for entering a search.
Declaration
Swift
@IBOutlet weak var searchTextField: UITextField?
-
The button to close the search mode.
Declaration
Swift
@IBOutlet weak var searchCloseButton: UIButton?
-
This contains the time selector items.
Declaration
Swift
@IBOutlet weak var timeSelectorContainerView: UIView?
-
The decrement time button
Declaration
Swift
@IBOutlet weak var leftButton: VMF_TapHoldButton?
-
The increment time button
Declaration
Swift
@IBOutlet weak var rightButton: VMF_TapHoldButton?
-
This displays the current time and day.
Declaration
Swift
@IBOutlet weak var timeDayDisplayLabel: UILabel?
-
The bottom constraint of the table display area. We use this to shrink the table area, when the keyboard is shown.
Declaration
Swift
@IBOutlet weak var bottomConstraint: NSLayoutConstraint?
-
This is a narrow bar, along the top, that shows how far into the day we are.
Declaration
Swift
@IBOutlet weak var completionBar: UIView?
-
The “Throbber” view
Declaration
Swift
@IBOutlet weak var throbber: UIView?
-
The double-tap gesture for bring us back to today.
Declaration
Swift
@IBOutlet weak var labelDoubleTapGesture: UITapGestureRecognizer?
-
The long-press gesture for selecting a weekday.
Declaration
Swift
@IBOutlet weak var weekdayLongPressGesture: UILongPressGestureRecognizer?
-
The long-press gesture for selecting a time.
Declaration
Swift
@IBOutlet weak var timeDayLongPressGesture: UILongPressGestureRecognizer?
-
The tap recognizer for entering direct selection mode.
Declaration
Swift
@IBOutlet weak var directSelectionTapRecognizer: UITapGestureRecognizer?
-
The container, for the Direct Selection Mode items.
Declaration
Swift
@IBOutlet weak var directSelectionItemsContainer: UIView?
-
The picker view, for the Direct Selection Mode.
Declaration
Swift
@IBOutlet weak var directSelectionPickerView: UIPickerView?
-
The button to exit Direct Selection Mode.
Declaration
Swift
@IBOutlet weak var directSelectionCloseButton: UIButton?
-
These are the meetings that are currently in progress. They are sorted in ascending local start time.
Declaration
Swift
var inProgressMeetings: [MeetingInstance] { get }
-
Returns now, in terms understood by the meeting search.
weekday is the current weekday, transformed to the meeting data (1 is Sunday) currentIntegerTime is the current time, as an integer (hours * 100 + minute).
Declaration
Swift
var nowIs: (weekday: Int, currentIntegerTime: Int) { get }
-
Returns true, if we need to force a reload from the server.
Declaration
Swift
var needsReload: Bool { get }
-
This recalculates all the meeting data, breaking it into a couple of sorted arrays.
Declaration
Swift
func reorganizeMeetings()
-
Called to load the meetings from the server.
Declaration
Swift
func loadMeetings(completion inCompletion: @escaping () -> Void)
Parameters
completion
A simple, no-parameter completion. It is always called in the main thread.
-
Get the meetings for a particular weekday.
Declaration
Swift
func getDailyMeetings(for inWeekdayIndex: Int) -> [Int : [MeetingInstance]]
Parameters
for
The 1-based (1 is Sunday) weekday index
Return Value
a Dictionary, with the weekday’s meetings, organized by localized start time (the key), which is expressed as military time (HHMM).
-
This returns a new destination controller to use for transitions.
NOTE: If the controller is in text search mode, then the name search controller is returned.
Declaration
Swift
func getTableDisplay(for inDayIndex: Int, time inTimeIndex: Int) -> VMF_EmbeddedTableController?
Parameters
for
The 0-based “day index.” If it is 0, though, it is the “in-progress” display.
time
The 0-based time index. This is the index of the currently selected time slot.
Return Value
A new (or reused) view controller, for the destination of the transition.
-
This returns a the meetings we should display, given the day and time.
NOTE: If the controller is in text search mode, then the search set is returned.
Declaration
Swift
func getCurentMeetings(for inDayIndex: Int = 0, time inTimeIndex: Int = 0) -> [MeetingInstance]
Parameters
for
The 0-based “day index.” If it is 0, though, it is the “in-progress” display.
time
The 0-based time index. This is the index of the currently selected time slot.
Return Value
A new (or reused) view controller, for the destination of the transition.
-
This opens the screen to a certain day index, and time (not index).
Declaration
Swift
func openTo(dayIndex inDayIndex: Int = -1, time inMilitaryTime: Int = 0)
Parameters
dayIndex
The 1-based (but 0 is in progress, 1-7 is Sunday through Saturday) day index. If omitted, then today/now is selected, and time is ignored.
time
The military time (HHMM), as an integer. If omitted, 12AM (0000) is assumed.
-
This returns the index of the time slot that is closest (before or after) to the given time and day.
Declaration
Swift
func getNearestIndex(dayIndex inDayIndex: Int = -1, time inMilitaryTime: Int = 0) -> Int
Parameters
dayIndex
The 1-based day index. If omitted, then today/now is selected, and time is ignored.
time
The military time (HHMM), as an integer. If omitted, 12AM (0000) is assumed.
Return Value
The index of the time slot closest to (or at the same time as) the given time. It may be prior.
-
This returns the time that corresponds to the day and time presented.
Declaration
Swift
func getTimeOf(dayIndex inDayIndex: Int = -1, timeIndex inTimeIndex: Int = 0) -> Int?
Parameters
dayIndex
The 1-based day index.
timeIndex
The index, as a 0-based integer.
Return Value
The time, as a military time integer, of the time slot for the given time. Returns nil, if the time can’t be found.
-
This updates the “thermometer” display in the time selector.
Declaration
Swift
func updateThermometer(_ inTablePage: VMF_EmbeddedTableControllerProtocol?)
-
Sets the day picker to whatever the current day/time is.
Declaration
Swift
func setDayPicker()
-
This enables or disables the attendance item.
Declaration
Swift
func setAttendance()
-
The segmented switch that controls the current display mode, was hit.
Declaration
Swift
@IBAction func weekdayModeSelectorSegmentedSwitchHit(_ inSwitch: UISegmentedControl)
Parameters
inSwitch
The segmented switch.
-
Called when something changes in the search text field.
Declaration
Swift
@IBAction func searchTextChanged(_ inTextField: UITextField)
-
Called when the search close button is hit.
Declaration
Swift
@IBAction func searchCloseHit(_: Any)
-
The decrement time button was hit.
Declaration
Swift
@IBAction func leftButtonHit(_: Any)
-
The increment time button was hit.
Declaration
Swift
@IBAction func rightButtonHit(_: Any)
-
The double-tap gesture recognizer on the weekday/time display label was triggered.
This resets the screen to today/now.
Declaration
Swift
@IBAction func doubleTapOnDayTimeLabel(_: Any)
-
A long-press on the weekday switch was detected. We change the weekday (we do not change to in-progress or search).
Declaration
Swift
@IBAction func longPressGestureInWeekdaySwitchDetected(_ inGestureRecognizer: UILongPressGestureRecognizer)
Parameters
inGestureRecognizer
The gesture recognizer that was triggered.
-
A long-press on the day/time display label switch was detected. We change the time slot.
Declaration
Swift
@IBAction func longPressGestureInDisplayLabelDetected(_ inGestureRecognizer: UILongPressGestureRecognizer)
Parameters
inGestureRecognizer
The gesture recognizer that was triggered.
-
The weekday/time label was touched.
Declaration
Swift
@IBAction func directSelectionOpen(_: Any)
-
The close button for the direct selection mode was hit.
Declaration
Swift
@IBAction func directSelectionCloseButtonHit(_: Any)
-
This is called just before the keyboard shows. We use this to “nudge” the table bottom up.
Declaration
Swift
@objc func keyboardWillShow(notification inNotification: NSNotification)
Parameters
notification
The notification being passed in.
-
This is called just before the keyboard shows. We use this to return the table bottom to its original position.
Declaration
Swift
@objc func keyboardWillHide(notification: NSNotification)
Parameters
notification
The notification being passed in.
-
Reloads all the meetings.
Declaration
Swift
func refreshCalled(completion inCompletion: @escaping () -> Void)
Parameters
completion
A simple empty callback. Always called in the main thread.
-
Called when the view hierarchy loads.
Declaration
Swift
override func viewDidLoad()
-
Called just before the view is to appear.
Declaration
Swift
override func viewWillAppear(_ inIsAnimated: Bool)
Parameters
inIsAnimated
True, if the appearance is animated.
-
Called just after the view appears.
Declaration
Swift
override func viewDidAppear(_ inIsAnimated: Bool)
Parameters
inIsAnimated
True, if the appearance is animated.
-
Called when the subviews are laid out. We use this to ensure that our segmented switch is set up correctly.
Declaration
Swift
override func viewDidLayoutSubviews()
-
Called just before the view disappears.
Declaration
Swift
override func viewWillDisappear(_ inIsAnimated: Bool)
Parameters
inIsAnimated
True, if the disappearance is animated.
-
Called before transitioning to another view controller.
Declaration
Swift
override func prepare(for inSegue: UIStoryboardSegue, sender: Any?)
Parameters
for
The segue instance.
sender
ignored.
-
Called to fetch the view controller before the current one.
Declaration
Swift
func pageViewController(_: UIPageViewController, viewControllerBefore inBeforeViewController: UIViewController) -> UIViewController?
Parameters
viewControllerBefore
The view controller after (to the right of) the one we want.
Return Value
A new (or reused) view controller to appear before (to the left of) the “before” controller.
-
Called to fetch the view controller after the current one.
Declaration
Swift
func pageViewController(_: UIPageViewController, viewControllerAfter inAfterViewController: UIViewController) -> UIViewController?
Parameters
viewControllerBefore
The view controller before (to the left of) the one we want.
Return Value
A new (or reused) view controller to appear after (to the right of) the “before” controller.
-
Called when a swipe transition is done. The only thing we do here, is reset our trackers.
Declaration
Swift
func pageViewController(_: UIPageViewController, didFinishAnimating: Bool, previousViewControllers: [UIViewController], transitionCompleted inIsDone: Bool)
Parameters
didFinishAnimating
The animation is complete (ignored)
previousViewControllers
A list of previous view controllers (also ignored)
transitionCompleted
True, if the transition completed, and was not aborted.
-
This enumerates the two PickerView components.
See moreDeclaration
Swift
enum PickerViewComponents : Int
-
This returns the number of components in the picker view.
Declaration
Swift
func numberOfComponents(in: UIPickerView) -> Int
Parameters
in
The picker view (ignored).
Return Value
2 (always)
-
This returns the number of rows in each component.
Declaration
Swift
func pickerView(_ inPickerView: UIPickerView, numberOfRowsInComponent inComponent: Int) -> Int
Parameters
numberOfRowsInComponent
The 0-based component index. Component 0 is the weekday, and Component 1, is the time slots for that weekday.
Return Value
7 (Component 0), or the number of time slots for the selected weekday (usually around 70).
-
This returns the title for the selected row, as a label.
Declaration
Swift
func pickerView(_ inPickerView: UIPickerView, viewForRow inRow: Int, forComponent inComponent: Int, reusing inReusing: UIView?) -> UIView
Parameters
inPickerView
The picker view.
titleForRow
The 0-based row index.
forComponent
The 0-based component index.
reusing
Any previously allocated view, to be reused.
Return Value
a view (a label), with the title for the indicated row.
-
Get the width of a component.
Declaration
Swift
func pickerView(_: UIPickerView, widthForComponent: Int) -> CGFloat
Parameters
widthForComponent
The 0-based component index.
Return Value
The width, in display units, of the component.
-
Called when a row is selected in the picker.
Declaration
Swift
func pickerView(_ inPickerView: UIPickerView, didSelectRow inRow: Int, inComponent: Int)
Parameters
inPickerView
The picker view.
didSelectRow
The 0-based row index.
inComponent
The 0-based component index.