<commit_before>//
//  NotificationBanner.swift
//  CWNotificationBanner
//
//  Created by <NAME> on 12/04/2016.
//  Copyright © 2016 <NAME>, Ltd. All rights reserved.
//

import UIKit
import SwiftyTimer

public let NotificationBannerShouldDisplayErrorNotification = "NotificationBannerShouldDisplayErrorNotification"

public func ==(lhs: Message, rhs: Message) -> Bool {
    return lhs.text == rhs.text && (lhs.date == rhs.date || (lhs.isError && rhs.isError))
}

public enum MessageType: String {
    case NoConnection = "No network connection."
    case ServerError = "Error connecting to the server."
    case Unspecified = "We couldn't complete that request."
    case NotLoggedIn = "Error: Please log out and log in again to continue."
}

public enum PushPayloadKey: String {
    case aps = "aps"
    case alert = "alert"
    case action = "a"
    case duration = "d"
}

public typealias MessageAction = (() -> ())

public struct Message: Equatable {
    public let text: String
    private let date: NSDate
    public let duration: NSTimeInterval
    public var actionKey: String?
    private let isError: Bool
    private static let defaultDisplayTime: NSTimeInterval = 5
    private static var actions = [String:MessageAction]()
    
    public init(text: String, displayDuration: NSTimeInterval = defaultDisplayTime, actionKey: String? = nil, isError error: Bool = false) {
        self.text = text
        self.date = NSDate()
        self.duration = displayDuration
        self.actionKey = actionKey
        self.isError = error
    }
    
    public init?(pushPayload: [NSObject : AnyObject]) {
        
        guard let text = pushPayload[PushPayloadKey.aps.rawValue]?[PushPayloadKey.alert.rawValue] as? String else { return nil }
        
        self.text = text
        self.date = NSDate()
        self.actionKey = pushPayload[PushPayloadKey.action.rawValue] as? String
        self.duration = pushPayload[PushPayloadKey.duration.rawValue] as? NSTimeInterval ?? Message.defaultDisplayTime
        self.isError = false
    }
    
    public static func registerAction(action: MessageAction, forKey key: String) {
        actions[key] = action
    }
    
    public static func registerActionsAndKeys(actionsAndKeys:[String:MessageAction]) {
        for (key, action) in actionsAndKeys {
            actions[key] = action
        }
    }
    
    public static func unregisterActionForKey(key: String) {
        actions.removeValueForKey(key)
    }
    
    public func isEqual(other: AnyObject?) -> Bool {
        guard let o = other as? Message else { return false }
        return o.text == text && o.date == date
    }
}

public class NotificationBanner: UIView {
    
    public static var animateDuration: NSTimeInterval = 0.3
    public static var fallbackToBannerOnMainWindow: Bool = false
    public var errorBackgroundColor = UIColor(white: 0.2, alpha: 1.0)
    public var regularBackgroundColor = UIColor.greenColor()
    
    override public var backgroundColor: UIColor! {
        didSet {
            underStatusBarView?.backgroundColor = backgroundColor?.colorWithAlphaComponent(0.85)
        }
    }
    
    public static func showMessage(message: Message) {
        
        guard NSThread.mainThread() == NSThread.currentThread() else {
            NSOperationQueue.mainQueue().addOperationWithBlock {
                showMessage(message)
            }
            return
        }
        
        // Don't interrupt an error to show a non-error
        if let currentMessage = pendingMessages.last where currentMessage.isError {
            let index = pendingMessages.count >= 2 ? pendingMessages.count - 2 : 0
            pendingMessages.insert(message, atIndex: index)
            return
        }
        
        // If we're interrupting a message to show an error, re-insert the old message so we show it again
        if let timer = currentMessageTimer,
            let interruptedMessage = pendingMessages.last where timer.valid {
            let index = pendingMessages.count >= 2 ? pendingMessages.count - 2 : 0
            pendingMessages.insert(interruptedMessage, atIndex: index)
        }
        
        if !pendingMessages.contains(message) {
            pendingMessages.append(message)
        }
        
        sharedToolbar.styleForError(message.isError)
        sharedToolbar.frame = messageHiddenFrame
        sharedToolbar.messageLabel.text = message.text
        
        UIView.animateWithDuration(animateDuration) { 
            sharedToolbar.frame = messageShownFrame
        }
        
        currentMessageTimer?.invalidate()
        currentMessageTimer = NSTimer.after(message.duration) {<commit_msg>Show the banner from underneath the nav bar by default; fall back to the main window if we can't find a nav controlelr<commit_after>//
//  NotificationBanner.swift
//  CWNotificationBanner
//
//  Created by <NAME> on 12/04/2016.
//  Copyright © 2016 <NAME>, Ltd. All rights reserved.
//

import UIKit
import SwiftyTimer

public let NotificationBannerShouldDisplayErrorNotification = "NotificationBannerShouldDisplayErrorNotification"

public func ==(lhs: Message, rhs: Message) -> Bool {
    return lhs.text == rhs.text && (lhs.date == rhs.date || (lhs.isError && rhs.isError))
}

public enum MessageType: String {
    case NoConnection = "No network connection."
    case ServerError = "Error connecting to the server."
    case Unspecified = "We couldn't complete that request."
    case NotLoggedIn = "Error: Please log out and log in again to continue."
}

public enum PushPayloadKey: String {
    case aps = "aps"
    case alert = "alert"
    case action = "a"
    case duration = "d"
}

public typealias MessageAction = (() -> ())

public struct Message: Equatable {
    public let text: String
    private let date: NSDate
    public let duration: NSTimeInterval
    public var actionKey: String?
    private let isError: Bool
    private static let defaultDisplayTime: NSTimeInterval = 5
    private static var actions = [String:MessageAction]()
    
    public init(text: String, displayDuration: NSTimeInterval = defaultDisplayTime, actionKey: String? = nil, isError error: Bool = false) {
        self.text = text
        self.date = NSDate()
        self.duration = displayDuration
        self.actionKey = actionKey
        self.isError = error
    }
    
    public init?(pushPayload: [NSObject : AnyObject]) {
        
        guard let text = pushPayload[PushPayloadKey.aps.rawValue]?[PushPayloadKey.alert.rawValue] as? String else { return nil }
        
        self.text = text
        self.date = NSDate()
        self.actionKey = pushPayload[PushPayloadKey.action.rawValue] as? String
        self.duration = pushPayload[PushPayloadKey.duration.rawValue] as? NSTimeInterval ?? Message.defaultDisplayTime
        self.isError = false
    }
    
    public static func registerAction(action: MessageAction, forKey key: String) {
        actions[key] = action
    }
    
    public static func registerActionsAndKeys(actionsAndKeys:[String:MessageAction]) {
        for (key, action) in actionsAndKeys {
            actions[key] = action
        }
    }
    
    public static func unregisterActionForKey(key: String) {
        actions.removeValueForKey(key)
    }
    
    public func isEqual(other: AnyObject?) -> Bool {
        guard let o = other as? Message else { return false }
        return o.text == text && o.date == date
    }
}

public class NotificationBanner: UIView {
    
    public static var animateDuration: NSTimeInterval = 0.3
    public static var fallbackToBannerOnMainWindow: Bool = false
    public var errorBackgroundColor = UIColor(white: 0.2, alpha: 1.0)
    public var regularBackgroundColor = UIColor.greenColor()
    
    override public var backgroundColor: UIColor! {
        didSet {
            underStatusBarView?.backgroundColor = backgroundColor?.colorWithAlphaComponent(0.85)
        }
    }
    
    public static func showMessage(message: Message) {
        
        guard NSThread.mainThread() == NSThread.currentThread() else {
            NSOperationQueue.mainQueue().addOperationWithBlock {
                showMessage(message)
            }
            return
        }
        
        // Don't interrupt an error to show a non-error
        if let currentMessage = pendingMessages.last where currentMessage.isError {
            let index = pendingMessages.count >= 2 ? pendingMessages.count - 2 : 0
            pendingMessages.insert(message, atIndex: index)
            return
        }
        
        // If we're interrupting a message to show an error, re-insert the old message so we show it again
        if let timer = currentMessageTimer,
            let interruptedMessage = pendingMessages.last where timer.valid {
            let index = pendingMessages.count >= 2 ? pendingMessages.count - 2 : 0
            pendingMessages.insert(interruptedMessage, atIndex: index)
        }
        
        if !pendingMessages.contains(message) {
            pendingMessages.append(message)
        }
        
        sharedToolbar.styleForError(message.isError)
        sharedToolbar.frame = messageHiddenFrame
        sharedToolbar.messageLabel.text = message.text
        
        if let navController = activeNavigationController,
            let navBar = navController.navigationBar as? NavigationBar {
            navBar.extraView = sharedToolbar
            navController.navigationBar.insertSubview(sharedToolbar, atIndex: 0)
        }
        else if fallbackToBannerOnMainWindow {
            keyWindow.rootViewController?.view.addSubview(sharedToolbar)
        }
        else {
            return
        }
        
        currentMessage = message
        
        UIView.animateWithDuration(animateDuration) {
            sharedToolbar.frame = messageShownFrame
        }
        
        currentMessageTimer?.invalidate()
        currentMessageTimer = NSTimer.after(message.duration) {
{'fraction_non_alphanumeric': 0.08151353527221496, 'fraction_numerical': 0.0057361376673040155, 'mean_word_length': 2.5505537692032867, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 17, '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': '8748', 'n_tokens_mistral': 2680, 'n_tokens_neox': 2608, 'n_words': 738}