MainScreenViewController

class MainScreenViewController : UIViewController, UIPickerViewDelegate, UIPickerViewDataSource, TheBestClockAlarmViewDelegate

The entire app is basically handled by this one big fat View Controller. The idea is that users don’t leave the context to do their settings.

There are two screens that appear: The Appearance Editor (font, color), and the Alarm Editor (alarm time, activation, sound). These are actually hidden screens that appear over the main display screen.

Yeah, it’s a big ugly mess. Read the README to find out why the app is configured this way.

  • This struct will contain all the info we need to display our time and date.

    See more

    Declaration

    Swift

    struct TimeDateContainer
  • This struct will contain information about a song in our media library.

    See more

    Declaration

    Swift

    struct SongInfo
  • This is a list of a subset of fonts likely to be on the device. We want to reduce the choices for the user.

    Declaration

    Swift

    let screenForThese: [String]
  • This is the base font size for the ante meridian label near the top of the screen.

    Declaration

    Swift

    let amPmLabelFontSize: CGFloat
  • This is the base font size for the date display along the top.

    Declaration

    Swift

    let dateLabelFontSize: CGFloat
  • This is the base font size for the row of alarm buttons along the bottom of the screen.

    Declaration

    Swift

    let alarmsFontSize: CGFloat
  • This is the base font size for the various textual items in the Alarm Editor.

    Declaration

    Swift

    let alarmEditorTopFontSize: CGFloat
  • This is the font size for the alarm sound/music selection picker.

    Declaration

    Swift

    let alarmEditorSoundPickerFontSize: CGFloat
  • This is the base font size for the sound test button.

    Declaration

    Swift

    let alarmEditorSoundButtonFontSize: CGFloat
  • This is the UIPickerView that is used to select the font.

    Declaration

    Swift

    @IBOutlet
    weak var fontDisplayPickerView: UIPickerView!
  • This is the UIPickerView that is used to select the color.

    Declaration

    Swift

    @IBOutlet
    weak var colorDisplayPickerView: UIPickerView!
  • This is the main view, holding the standard display items.

    Declaration

    Swift

    @IBOutlet
    weak var mainNumberDisplayView: UIView!
  • This is a normally hidden view that holds the color and font selection UIPickerViews

    Declaration

    Swift

    @IBOutlet
    weak var mainPickerContainerView: UIView!
  • This is the hidden slider for changing the brightness on the left side of the screen..

    Declaration

    Swift

    @IBOutlet
    weak var leftBrightnessSlider: TheBestClockVerticalBrightnessSliderView!
  • This is the hidden slider for changing the brightness on the right side of the screen..

    Declaration

    Swift

    @IBOutlet
    weak var rightBrightnessSlider: TheBestClockVerticalBrightnessSliderView!
  • This is the label that displays ante meridian (AM/PM).

    Declaration

    Swift

    @IBOutlet
    weak var amPmLabel: UILabel!
  • This is the label that displays today’s date.

    Declaration

    Swift

    @IBOutlet
    weak var dateDisplayLabel: UILabel!
  • This view will hold our alarm displays.

    Declaration

    Swift

    @IBOutlet
    weak var alarmContainerView: UIView!
  • This is a view that will cover the screen if the user wants to edit an alarm.

    Declaration

    Swift

    @IBOutlet
    weak var editAlarmScreenContainer: UIView!
  • This is the date picker in the alarm time editor.

    Declaration

    Swift

    @IBOutlet
    weak var editAlarmTimeDatePicker: UIDatePicker!
  • This will be the container for the flashing view that appears when there’s an alarm.

    Declaration

    Swift

    @IBOutlet
    weak var alarmDisplayView: UIView!
  • This is the view that will actually display the flashes.

    Declaration

    Swift

    @IBOutlet
    weak var flasherView: UIView!
  • This is the invisible button that we use to dismiss the alarm editor.

    Declaration

    Swift

    @IBOutlet
    weak var dismissAlarmEditorButton: UIButton!
  • This is a partial mask view for our alarm editor screen.

    Declaration

    Swift

    @IBOutlet
    weak var editAlarmScreenMaskView: UIView!
  • This is the little more info button that is displayed at the bottom of the setup screen.

    Declaration

    Swift

    @IBOutlet
    weak var infoButton: UIButton!
  • This switch will denote the active state of the alarm.

    Declaration

    Swift

    @IBOutlet
    weak var alarmEditorActiveSwitch: UISwitch!
  • This is the localized label for that switch, but we make it a button, so it can be used to trigger the switch.

    Declaration

    Swift

    @IBOutlet
    weak var alarmEditorActiveButton: UIButton!
  • This is the switch that selects whether or not to use a vibration (on supported devices).

    Declaration

    Swift

    @IBOutlet
    weak var alarmEditorVibrateBeepSwitch: UISwitch!
  • This is the localized label for that switch, but we make it a button, so it can be used to trigger the switch.

    Declaration

    Swift

    @IBOutlet
    weak var alarmEditorVibrateButton: UIButton!
  • This is the segmented switch that selects the type of sounds we’ll use.

    Declaration

    Swift

    @IBOutlet
    weak var alarmEditSoundModeSelector: UISegmentedControl!
  • This is the picker view we use to select playback sounds for the alarm.

    Declaration

    Swift

    @IBOutlet
    weak var editAlarmPickerView: UIPickerView!
  • This is the button that is pressed to test the sounds.

    Declaration

    Swift

    @IBOutlet
    weak var editAlarmTestSoundButton: TheBestClockSpeakerButton!
  • This is the STOP long press gesture recognizer.

    Declaration

    Swift

    @IBOutlet
    var shutUpAlreadyLongPressGestureRecognizer: UILongPressGestureRecognizer!
  • This is the STOP double-tap gesture recognizer.

    Declaration

    Swift

    @IBOutlet
    var shutUpAlreadyDoubleTapRecognizer: UITapGestureRecognizer!
  • This is the snooze tap gesture recognizer.

    Declaration

    Swift

    @IBOutlet
    var snoozeGestureRecogninzer: UITapGestureRecognizer!
  • This is a view that we temorarily put up while fetching the music collection.

    Declaration

    Swift

    @IBOutlet
    weak var musicLookupThrobberView: UIView!
  • This is the throbber in that view.

    Declaration

    Swift

    @IBOutlet
    weak var musicLookupThrobber: UIActivityIndicatorView!
  • This is the secondary picker view for selecting songs in the Alarm Editor.

    Declaration

    Swift

    @IBOutlet
    weak var songSelectionPickerView: UIPickerView!
  • This is a special view that we use to mask the entire screen for initial music load.

    Declaration

    Swift

    @IBOutlet
    weak var wholeScreenThrobberView: UIView!
  • This is the throbber in that screen.

    Declaration

    Swift

    @IBOutlet
    weak var wholeScreenThrobber: UIActivityIndicatorView!
  • This is the view that holds the test song button.

    Declaration

    Swift

    @IBOutlet
    weak var musicTestButtonView: UIView!
  • This is the test song button.

    Declaration

    Swift

    @IBOutlet
    weak var musicTestButton: TheBestClockSpeakerButton!
  • This is a container view for the main edit alarm picker (Sounds and Artists).

    Declaration

    Swift

    @IBOutlet
    weak var editPickerContainerView: UIView!
  • Thi is a container for the secondary music picker (songs)

    Declaration

    Swift

    @IBOutlet
    weak var songSelectContainerView: UIView!
  • This is a container for the test sound button.

    Declaration

    Swift

    @IBOutlet
    weak var testSoundContainerView: UIView!
  • This view is displayed when there is no music available.

    Declaration

    Swift

    @IBOutlet
    weak var noMusicDisplayView: UIView!
  • This is the label that specifies that there is no music available.

    Declaration

    Swift

    @IBOutlet
    weak var noMusicAvailableLabel: UILabel!
  • This label tells the user that the alarm will not go off until next time.

    Declaration

    Swift

    @IBOutlet
    weak var alarmDeactivatedLabel: UILabel!
  • This is a transparent view that allows gesture recognizers to disable the alarm.

    Declaration

    Swift

    @IBOutlet
    weak var alarmDisableScreenView: UIView!
  • This is the label that is displayed while the music is being looked up.

    Declaration

    Swift

    @IBOutlet
    weak var musicLookupLabel: UILabel!
  • This is set to true if an alarm goes off. We then check it to see if we need to stop a playing audio loop when the alarm ends. Otherwise, we could keep playing forever.

    Declaration

    Swift

    var alarmSounded: Bool
  • These are the persistent prefs that store our settings.

    Declaration

    Swift

    var prefs: TheBestClockPrefs!
  • If the Alarm Editor is open, then this is the index of the alarm being edited. It is -1 if the Alarm Editor is not open.

    Declaration

    Swift

    var currentlyEditingAlarmIndex: Int
  • This is the currently selected main font. It’s an index into our font selection Array.

    Declaration

    Swift

    var selectedFontIndex: Int
  • This is an index into our color selection Array, denoting the color we have selected.

    Declaration

    Swift

    var selectedColorIndex: Int
  • This indicates the brightness level of the screen.

    Declaration

    Swift

    var selectedBrightness: CGFloat
  • This is an Array of the button objects that we generated for the alarms along the bottom of the screen.

    Declaration

    Swift

    var alarmButtons: [TheBestClockAlarmView]
  • These are the names of the fonts that we have selected to be choices.

    Declaration

    Swift

    var fontSelection: [String]
  • These are all the UIColors that we have to choose from. They are dynamically generated.

    Declaration

    Swift

    var colorSelection: [UIColor]
  • These are URL Strings of the various sound files we have for the sounds setting.

    Declaration

    Swift

    var soundSelection: [String]
  • This is the basic background color for the whole kit and kaboodle. It gets darker as the brightness is reduced.

    Declaration

    Swift

    var backgroundColor: UIColor
  • This is the heartbeat of the clock. It’s a 1-second repeating timer.

    Declaration

    Swift

    var timer: Timer!
  • This is used to cache the selected main font size. We sort of use it as a semaphore.

    Declaration

    Swift

    var fontSizeCache: CGFloat
  • This contains information about music items.

    Declaration

    Swift

    var songs: [String : [MainScreenViewController.SongInfo]]
  • This is an index of the keys (artists) for the songs Dictionary.

    Declaration

    Swift

    var artists: [String]
  • This is the narrowest that a screen can be to properly accommodate an Alarm Editor. Under this, and we need to force portrait mode.

    Declaration

    Swift

    var alarmEditorMinimumHeight: CGFloat
  • This is a simple semaphore to indicate that we are in the process of loading music.

    Declaration

    Swift

    var isLoadin: Bool
  • This records the number of snoozes. We use this if we don’t have forever snooze on.

    Declaration

    Swift

    var snoozeCount: Int
  • This will provide haptic/audio feedback for opening and closing the editors, and for ending alarms.

    Declaration

    Swift

    var impactFeedbackGenerator: UIImpactFeedbackGenerator?
  • This will provide haptic/audio feedback for selection ticks.

    Declaration

    Swift

    var selectionFeedbackGenerator: UISelectionFeedbackGenerator?
  • This will be the audio player that we use to play the alarm sound.

    Declaration

    Swift

    var audioPlayer: AVAudioPlayer? { get set }
  • There can only be one…

    Declaration

    Swift

    func numberOfComponents(in inPickerView: UIPickerView) -> Int

    Parameters

    in

    The UIPickerView being queried.

    Return Value

    1 (all the time)

  • This simply returns the number of rows in the pickerview. It will switch on which picker is calling it.

    Declaration

    Swift

    func pickerView(_ inPickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int

    Parameters

    inPickerView

    The UIPickerView being queried.

  • This will send the proper height for the picker row. The color picker is small squares.

    Declaration

    Swift

    func pickerView(_ inPickerView: UIPickerView, rowHeightForComponent component: Int) -> CGFloat

    Parameters

    inPickerView

    The UIPickerView being queried.

  • This generates one row’s content, depending on which picker is being specified.

    Declaration

    Swift

    func pickerView(_ inPickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing inView: UIView?) -> UIView

    Parameters

    inPickerView

    The UIPickerView being queried.

  • This is called when a picker row is selected, and sets the value for that picker.

    Declaration

    Swift

    func pickerView(_ inPickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int)

    Parameters

    inPickerView

    The UIPickerView being queried.

  • This is called when we want to access the music library to make a list of artists and songs.

    Declaration

    Swift

    func loadMediaLibrary(displayWholeScreenThrobber inDisplayWholeScreenThrobber: Bool = false, forceReload inForceReload: Bool = false)

    Parameters

    displayWholeScreenThrobber

    If true (default is false), then the big throbber screen will show while this is loading.

    forceReload

    If true (default is false), then the entire music library will be reloaded, even if we already have it.

  • This loads the music, assuming that we have been authorized.

    Declaration

    Swift

    func loadUpOnMusic()
  • This is called after the music has been loaded. It sets up the Alarm Editor.

    Declaration

    Swift

    func dunLoadin()
  • This reads all the user’s music, and sorts it into a couple of bins for us to reference later.

    Declaration

    Swift

    func loadSongData(_ inSongs: [MPMediaItemCollection])

    Parameters

    inSongs

    The list of songs we read in, as media items.

  • This is called to play a sound, choosing from the various alarms. That alarm’s indexed sound will be used.

    Declaration

    Swift

    func playSound(_ inAlarmIndex: Int)

    Parameters

    inAlarmIndex

    This is the index of the alarm that we want to use to play the sound.

  • This plays any sound, using a given URL.

    Declaration

    Swift

    func playThisSound(_ inSoundURL: URL)

    Parameters

    inSoundURL

    This is the URI to the sound resource.

  • If the audio player is going, this pauses it. Nothing happens if no audio player is going.

    Declaration

    Swift

    func pauseAudioPlayer()
  • This terminates the audio player. Nothing happens if no audio player is going.

    Declaration

    Swift

    func stopAudioPlayer()
  • Declaration

    Swift

    func showLargeLookupThrobber()
  • Declaration

    Swift

    func hideLargeLookupThrobber()
  • This creates the display, as a gradient-filled font.

    Declaration

    Swift

    func createDisplayView(_ inContainerView: UIView, index inIndex: Int) -> UIView
  • This sets (or clears) the ante meridian label. We use a solid bright text color.

    Declaration

    Swift

    func setAMPMLabel()
  • This sets the date label. We use a solid bright text color.

    Declaration

    Swift

    func setDateDisplayLabel()
  • This creates and links up the row of buttons along the bottom of the screen.

    Declaration

    Swift

    func setUpAlarms()
  • This updates the alarm buttons to reflect the brightness, color and font.

    Declaration

    Swift

    func updateAlarms()
  • This adds a single new alarm button to the bottom strip.

    We use this, so the buttons get autolayout constraints.

    Declaration

    Swift

    func addAlarmView(_ inSubView: TheBestClockAlarmView, percentage inPercentage: CGFloat, previousView inPreviousView: TheBestClockAlarmView!)

    Parameters

    inSubView

    The button to add.

    percentage

    The width, as a percentage (0 -> 1.0) of the total strip width, of the subview.

    previousView

    If there was a view to the left, this is it.

  • This scans the alarms, and looks for anyone that wants to ring their bell.

    Declaration

    Swift

    func checkAlarmStatus(soundOnly: Bool = false)

    Parameters

    soundOnly

    If true (default is false), then this will not flash the display, and will only trigger the sound.

  • This plays whatever alarm is supposed to be alarming. This will vibrate, if we are set to do that.

    Declaration

    Swift

    func aooGah(_ inIndex: Int)

    Parameters

    inIndex

    This is the index of the alarm to be played.

  • This flashes the display in a fading animation.

    Declaration

    Swift

    func flashDisplay(_ inUIColor: UIColor)

    Parameters

    inUIColor

    This is the color to flash.

  • This starts our regular 1-second ticker.

    Declaration

    Swift

    func startTicker()
  • This stops our regular 1-second ticker.

    Declaration

    Swift

    func stopTicker()
  • This simply redraws the main time and the two adjacent labels.

    Declaration

    Swift

    func updateMainTime()
  • This is called from the timer.

    Declaration

    Swift

    func checkTicker()
  • This is called at load time, to add the various localized accessibility labels and hints to our elements on the main display screen.

    Declaration

    Swift

    func setUpMainScreenAccessibility()
  • This is called at load time, to add the various localized accessibility labels and hints to our elements in the Appearance Editor screen.

    Declaration

    Swift

    func setUpAppearanceEditorAccessibility()
  • This is called at load time, to add the various localized accessibility labels and hints to our elements in the Alarm Editor screen.

    Declaration

    Swift

    func setUpAlarmEditorAccessibility()
  • This is called to update the color of the info button in the Appearance Editor.

    Declaration

    Swift

    func setInfoButtonColor()
  • This is called when the app is reactivated.

    It resets all the deactivations snoozes.

    Declaration

    Swift

    func turnOffDeactivations()
  • This is called when the user taps in an alarm active screen.

    Declaration

    Swift

    @IBAction
    func hitTheSnooze(_: UITapGestureRecognizer)
  • This is called when the user long-presses in an alarm active screen.

    Declaration

    Swift

    @IBAction
    func shutUpAlready(_: Any! = nil)
  • This is called when the user taps in an alarm on the main screen, toggling it.

    Declaration

    Swift

    @IBAction
    func alarmActiveStateChanged(_ inSender: TheBestClockAlarmView)

    Parameters

    inSender

    The alarm button that was hit.

  • This is called when a brightness slider is changed.

    Declaration

    Swift

    @IBAction
    func brightnessSliderChanged(_ inSlider: TheBestClockVerticalBrightnessSliderView! = nil)

    Parameters

    inSlider

    The brightness slider being manipulated.

  • This is called when a slider opens, so we don’t have the situation where both are open at once.

    Declaration

    Swift

    @IBAction
    func brightnessSliderOpened(_ inSlider: TheBestClockVerticalBrightnessSliderView)

    Parameters

    inSlider

    The slider object that called this

  • This is called when an open slider closes. We re-enable both sliders.

    Declaration

    Swift

    @IBAction
    func brightnessSliderClosed(_: Any)
  • This is called when we first open the Appearance (font and color) Editor.

    Declaration

    Swift

    @IBAction
    func openAppearanceEditor(_: Any)
  • This is called when the user taps in the info button.

    Declaration

    Swift

    @IBAction
    func openInfo(_: Any)
  • This is called to close the Appearance Editor.

    Declaration

    Swift

    @IBAction
    func closeAppearanceEditor(_: Any)
  • This is called when the resources and storyboard are all loaded up for the first time. We use this to initialize most of our settings.

    Declaration

    Swift

    override func viewDidLoad()
  • This is called when we are about to layout our views (like when we rotate). We redraw everything, and force a new font size setting by zeroing the cache.

    Declaration

    Swift

    override func viewDidLayoutSubviews()
  • This is called when the view is about to appear. We make sure that we redraw everything with a zeroed cache, and start the don’t sleep thingy. We also start a one-second timer.

    Declaration

    Swift

    override func viewWillAppear(_ animated: Bool)
  • When the view will disappear, we stop the caffiene drip, and the timer.

    Declaration

    Swift

    override func viewWillDisappear(_ animated: Bool)
  • When the view will disappear, we stop the caffiene drip, and the timer.

    Declaration

    Swift

    override func prepare(for segue: UIStoryboardSegue, sender: Any?)
  • This is called to open the Alarm Editor for an indexed alarm.

    Declaration

    Swift

    func openAlarmEditor(_ inAlarmIndex: Int)

    Parameters

    inAlarmIndex

    0-2. The index of the alarm to be edited.