<commit_before>import MultipeerConnectivity
import UIKit

class SCAccessCodeViewController: SCViewController {
    private let allowedCharactersSet = NSCharacterSet(charactersInString: Room.accessCodeAllowedCharacters as String)
    private let defaultTimeoutInterval: NSTimeInterval = 10
    private let shortTimeoutInterval: NSTimeInterval = 3

    private let firstTag = 0
    private let lastTag = 3

    private var timeoutTimer: NSTimer?
    private var refreshTimer: NSTimer?

    private var lastTextFieldWasFilled = false
    private var keyboardDidShow = false

    private var accessCodeCharacters = NSMutableArray(capacity: SCConstants.accessCodeLength)

    @IBOutlet weak var statusLabel: SCStatusLabel!
    @IBOutlet weak var textFieldsView: UIView!
    @IBOutlet weak var browseLobbyButton: UIButton!
    @IBOutlet weak var headerTopMarginConstraint: NSLayoutConstraint!
    @IBOutlet weak var contentViewVerticalCenterConstraint: NSLayoutConstraint!
    @IBOutlet weak var statusLabelTopMarginConstraint: NSLayoutConstraint!

    // MARK: Actions
    @IBAction func unwindToAccessCode(sender: UIStoryboardSegue) {
        super.unwindedToSelf(sender)
    }

    @IBAction func onBrowseLobbyTapped(sender: AnyObject) {
        self.performSegueWithIdentifier("lobby-room", sender: self)
    }

    @IBAction func onBackButtonTapped(sender: AnyObject) {
        super.performUnwindSegue(false, completionHandler: nil)
    }

    deinit {
        print("[DEINIT] " + NSStringFromClass(self.dynamicType))
    }

    // MARK: Lifecycle
    override func viewDidLoad() {
        super.viewDidLoad()

        self.restoreStatus()
    }

    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)

        // Unwindable view controller identifier
        self.unwindableIdentifier = "access-code"

        SCMultipeerManager.instance.delegate = self

        for view in textFieldsView.subviews as [UIView] {
            if let textField = view as? SCSingleCharacterTextField {
                textField.delegate = self
                textField.backspaceDelegate = self
                textField.addTarget(self, action: #selector(SCAccessCodeViewController.textFieldDidChange), forControlEvents: .EditingChanged)

                // Tags are assigned in the Storyboard
                if textField.tag == self.firstTag {
                    textField.becomeFirstResponder()
                }
            }
        }
    }

    override func viewWillDisappear(animated: Bool) {
        super.viewWillDisappear(animated)

        self.refreshTimer?.invalidate()

        for view in textFieldsView.subviews as [UIView] {
            if let textField = view as? SCSingleCharacterTextField {
                textField.delegate = nil
                textField.backspaceDelegate = nil
                textField.removeTarget(self, action: #selector(SCAccessCodeViewController.textFieldDidChange), forControlEvents: .EditingChanged)
                textField.text = nil

                if textField.isFirstResponder() {
                    textField.resignFirstResponder()
                }
            }
        }
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    // MARK: Segue
    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        super._prepareForSegue(segue, sender: sender)
    }

    // MARK: Keyboard
    override func keyboardWillShow(notification: NSNotification) {
        if self.keyboardDidShow {
            return
        }

        if let userInfo = notification.userInfo, let frame = userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue {
            self.keyboardDidShow = true

            let rect = frame.CGRectValue()
            self.contentViewVerticalCenterConstraint.constant = -(rect.height / 2 - self.headerTopMarginConstraint.constant - self.statusLabelTopMarginConstraint.constant)
        }
    }

    override func keyboardWillHide(notification: NSNotification) {
        self.keyboardDidShow = false

        self.contentViewVerticalCenterConstraint.constant = 0
    }

    // MARK: Private
    @objc
    private func onTimeout() {
        self.timeoutTimer?.invalidate()
        SCMultipeerManager.instance.stopAdvertiser()

        self.statusLabel.text = SCStrings.failStatus
        self.browseLobbyButton.hidden = false
        self.timeoutTimer = NSTimer.scheduledTimerWithTimeInterval(self.shortTimeoutInterval, target: self, selector: #selector(SCAccessCodeViewController.restoreStatus), userInfo: nil, repeats: false)

        for view in textFieldsView.subviews as [UIView] {
            if let textField = view as? UITextField {
                textField.enabled = true
                textField.textColor = UIColor.blackColor()

                if textField.tag == self.lastTag {
                    textField.becomeFirstResponder()
                }
            }
        }
    }

    @objc
    private func restoreStatus() {
        self.statusLabel.text = SCStrings.normalAccessCodeStatus
    }

    @objc
    private func textFieldDidChange(textField: UITextField) {
        let currentTag = textField.tag

        if let character = textField.text where character.characters.count == 1 {
            self.accessCodeCharacters[currentTag] = character

            if currentTag == self.lastTag {
                let accessCode = self.accessCodeCharacters.componentsJoinedByString("")
                self.joinRoomWithAccessCode(accessCode)
                return<commit_msg>Address issue preventing access code from showing after timeout in night mode<commit_after>import MultipeerConnectivity
import UIKit

class SCAccessCodeViewController: SCViewController {
    private let allowedCharactersSet = NSCharacterSet(charactersInString: Room.accessCodeAllowedCharacters as String)
    private let defaultTimeoutInterval: NSTimeInterval = 10
    private let shortTimeoutInterval: NSTimeInterval = 3

    private let firstTag = 0
    private let lastTag = 3

    private var timeoutTimer: NSTimer?
    private var refreshTimer: NSTimer?

    private var lastTextFieldWasFilled = false
    private var keyboardDidShow = false

    private var accessCodeCharacters = NSMutableArray(capacity: SCConstants.accessCodeLength)

    @IBOutlet weak var statusLabel: SCStatusLabel!
    @IBOutlet weak var textFieldsView: UIView!
    @IBOutlet weak var browseLobbyButton: UIButton!
    @IBOutlet weak var headerTopMarginConstraint: NSLayoutConstraint!
    @IBOutlet weak var contentViewVerticalCenterConstraint: NSLayoutConstraint!
    @IBOutlet weak var statusLabelTopMarginConstraint: NSLayoutConstraint!

    // MARK: Actions
    @IBAction func unwindToAccessCode(sender: UIStoryboardSegue) {
        super.unwindedToSelf(sender)
    }

    @IBAction func onBrowseLobbyTapped(sender: AnyObject) {
        self.performSegueWithIdentifier("lobby-room", sender: self)
    }

    @IBAction func onBackButtonTapped(sender: AnyObject) {
        super.performUnwindSegue(false, completionHandler: nil)
    }

    deinit {
        print("[DEINIT] " + NSStringFromClass(self.dynamicType))
    }

    // MARK: Lifecycle
    override func viewDidLoad() {
        super.viewDidLoad()

        self.restoreStatus()
    }

    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)

        // Unwindable view controller identifier
        self.unwindableIdentifier = "access-code"

        SCMultipeerManager.instance.delegate = self

        for view in textFieldsView.subviews as [UIView] {
            if let textField = view as? SCSingleCharacterTextField {
                textField.delegate = self
                textField.backspaceDelegate = self
                textField.addTarget(self, action: #selector(SCAccessCodeViewController.textFieldDidChange), forControlEvents: .EditingChanged)

                // Tags are assigned in the Storyboard
                if textField.tag == self.firstTag {
                    textField.becomeFirstResponder()
                }
            }
        }
    }

    override func viewWillDisappear(animated: Bool) {
        super.viewWillDisappear(animated)

        self.refreshTimer?.invalidate()

        for view in textFieldsView.subviews as [UIView] {
            if let textField = view as? SCSingleCharacterTextField {
                textField.delegate = nil
                textField.backspaceDelegate = nil
                textField.removeTarget(self, action: #selector(SCAccessCodeViewController.textFieldDidChange), forControlEvents: .EditingChanged)
                textField.text = nil

                if textField.isFirstResponder() {
                    textField.resignFirstResponder()
                }
            }
        }
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    // MARK: Segue
    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        super._prepareForSegue(segue, sender: sender)
    }

    // MARK: Keyboard
    override func keyboardWillShow(notification: NSNotification) {
        if self.keyboardDidShow {
            return
        }

        if let userInfo = notification.userInfo, let frame = userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue {
            self.keyboardDidShow = true

            let rect = frame.CGRectValue()
            self.contentViewVerticalCenterConstraint.constant = -(rect.height / 2 - self.headerTopMarginConstraint.constant - self.statusLabelTopMarginConstraint.constant)
        }
    }

    override func keyboardWillHide(notification: NSNotification) {
        self.keyboardDidShow = false

        self.contentViewVerticalCenterConstraint.constant = 0
    }

    // MARK: Private
    @objc
    private func onTimeout() {
        self.timeoutTimer?.invalidate()
        SCMultipeerManager.instance.stopAdvertiser()

        self.statusLabel.text = SCStrings.failStatus
        self.browseLobbyButton.hidden = false
        self.timeoutTimer = NSTimer.scheduledTimerWithTimeInterval(self.shortTimeoutInterval, target: self, selector: #selector(SCAccessCodeViewController.restoreStatus), userInfo: nil, repeats: false)

        for view in textFieldsView.subviews as [UIView] {
            if let textField = view as? SCSingleCharacterTextField {
                textField.enabled = true
                textField.textColor = UIColor.spycodesGrayColor()

                if textField.tag == self.lastTag {
                    textField.becomeFirstResponder()
                }
            }
        }
    }

    @objc
    private func restoreStatus() {
        self.statusLabel.text = SCStrings.normalAccessCodeStatus
    }

    @objc
    private func textFieldDidChange(textField: UITextField) {
        let currentTag = textField.tag

        if let character = textField.text where character.characters.count == 1 {
            self.accessCodeCharacters[currentTag] = character

            if currentTag == self.lastTag {
                let accessCode = self.accessCodeCharacters.componentsJoinedByString("")
                self.joinRoomWithAccessCode(accessCode)
                return
{'fraction_non_alphanumeric': 0.06977992485238863, 'fraction_numerical': 0.0014313830738951511, 'mean_word_length': 2.6224886584575504, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1459363', 'n_tokens_mistral': 3029, 'n_tokens_neox': 2852, 'n_words': 638}