<commit_before>//
//  KeyboardViewController.swift
//  Keyboard
//
//  Created by <NAME> on 5/7/15.
//  Copyright (c) 2015 <NAME>. All rights reserved.
//

import UIKit
import RealmSwift
import ZLBalancedFlowLayout
import Cartography
import TTTAttributedLabel

let reuseIdentifier = "Cell", headerIdentifier = "header", footerIdentifier = "footer"
let appGroupId = "group.com.axcel.EmoticonKeyboard"

class KeyboardViewController: UIInputViewController {

    var collectionViews = UIView()
    var controlViews = UIView()

    var nextKeyboardButton: UIButton!
    var menuButton: UIButton!
    var spaceButton: UIButton!
    var enterButton: UIButton!
    var deleteButton: UIButton!
    
    var openAccessLabel = UILabel()

    var categoriesCollectionView: UICollectionView!
    var emoticonsCollectionView: UICollectionView!
    
    var categoriesCollectionViewDataSourceDelegate = EKCategoriesCollectionViewDataSourceDelegate()
    var emoticonsCollectionViewDataSourceDelegate = EKEmoticonsCollectionViewDataSourceDelegate()
    
    var rootCategories : Results<RootCategory>! {
        didSet {
            categoriesCollectionViewDataSourceDelegate.rootCategories = rootCategories
            categoriesCollectionView?.reloadData()
        }
    }
    var currentCategory: Category? {
        didSet {
            emoticonsCollectionViewDataSourceDelegate.category = currentCategory
            emoticonsCollectionView?.reloadData()
        }
    }
    
    var notificationToken: NotificationToken?
    
    // MARK: Input View Constraints
    let portraitHeight = 300, landscapeHeight = 200
    var heightConstraint: NSLayoutConstraint?
    var widthConstraint: NSLayoutConstraint?
    var isProtrait = true
    
    override func updateViewConstraints() {
        super.updateViewConstraints()
        
        // Add custom view sizing constraints here
        updateInputViewConstraints()
    }
    
    override func viewDidLayoutSubviews() {
        view.setNeedsUpdateConstraints()
    }
    
    override func viewDidAppear(animated: Bool) {
        super.viewDidAppear(animated)
        
        if isOpenAccessGranted() {
            openAccessLabel.hidden = true
        } else {
            openAccessLabel.hidden = false
        }
        
        isProtrait = UIScreen.mainScreen().bounds.width < UIScreen.mainScreen().bounds.height
        var height = isProtrait ? portraitHeight : landscapeHeight
        heightConstraint = NSLayoutConstraint(item: view!, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 0, constant: CGFloat(height))
        heightConstraint!.priority = 900
        view.addConstraint(heightConstraint!)
        
        widthConstraint = NSLayoutConstraint(item: view!, attribute: .Width, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 0, constant: UIScreen.mainScreen().bounds.width)
        widthConstraint!.priority = 950
        view.addConstraint(widthConstraint!)
    }
    
    func updateInputViewConstraints() {
        if self.view.frame.size.width == 0 || self.view.frame.size.height == 0 || isProtrait == (UIScreen.mainScreen().bounds.width < UIScreen.mainScreen().bounds.height) {
            return
        }
        if var heightConstraint = heightConstraint, widthConstraint = widthConstraint {
            view!.removeConstraint(heightConstraint)
            isProtrait = UIScreen.mainScreen().bounds.width < UIScreen.mainScreen().bounds.height
            var height = isProtrait ? portraitHeight : landscapeHeight
            self.heightConstraint!.constant = CGFloat(height)
            view!.addConstraint(heightConstraint)
            
            view!.removeConstraint(widthConstraint)
            self.widthConstraint!.constant = UIScreen.mainScreen().bounds.width
            view!.addConstraint(widthConstraint)
        }
    }
    
    // MARK: Life Cycle
    deinit {
        if let notificationToken = notificationToken {
            Realm().removeNotification(notificationToken)
        }
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Top level view containers
        for subview in [collectionViews, controlViews, openAccessLabel] {
            subview.setTranslatesAutoresizingMaskIntoConstraints(false)
            view.addSubview(subview)
        }
        view.backgroundColor = UIColor.whiteColor()
        
        openAccessLabel.text = "Please allow full access in Settings > General > Keyboard > Keyboards"
        openAccessLabel.numberOfLines = 0
        openAccessLabel.textColor = UIColor.blackColor()
        openAccessLabel.sizeToFit()
        openAccessLabel.hidden = true
        view.addSubview(openAccessLabel)
        
        view.setTranslatesAutoresizingMaskIntoConstraints(false)
        
        layout(collectionViews, controlViews) { view1, view2 in
            view1.left == view1.superview!.left
            view2.left == view1.left
            view1.right == view1.superview!.right
            view2.right == view1.right
            
            view1.top == view1.superview!.top
            view1.bottom  == view2.top
            view2.bottom == view2.superview!.bottom ~ 100
            view2.height  == 40 ~ 200
        }
        
        layout(openAccessLabel, collectionViews) { view1, view2 in
            view1.centerX == view2.centerX
            view1.centerY == view2.centerY
            view1.left == view1.superview!.left
            view1.right == view1.superview!.right
        }
        
        // Buttons: next menu space return delete
        nextKeyboardButton = UIButton.buttonWithType(.System) as! UIButton
        nextKeyboardButton.setTitle(NSLocalizedString("🌐", comment: "Title for 'Next Keyboard' button"), forState: .Normal)
        nextKeyboardButton.addTarget(self, action: "advanceToNextInputMode", forControlEvents: .TouchUpInside)
        
        menuButton = UIButton.buttonWithType(.System) as! UIButton
        menuButton.setTitle(NSLocalizedString("🚀", comment: "Title for 'Menu' button"), forState: .Normal)
        menuButton.addTarget(self, action: "showMenu", forControlEvents: .TouchUpInside)
        
        spaceButton = UIButton.buttonWithType(.System) as! UIButton
        spaceButton.setTitle(NSLocalizedString("Space", comment: "Title for 'Space' button"), forState: .Normal)
        spaceButton.addTarget(self, action: "insertSpace", forControlEvents: .TouchUpInside)

        enterButton = UIButton.buttonWithType(.System) as! UIButton
        enterButton.setTitle(NSLocalizedString("⏎", comment: "Title for 'Enter' button"), forState: .Normal)
        enterButton.addTarget(self, action: "insertReturn", forControlEvents: .TouchUpInside)
        
        deleteButton = UIButton.buttonWithType(.System) as! UIButton
        deleteButton.setTitle(NSLocalizedString("⌫", comment: "Title for 'Delete' button"), forState: .Normal)
        deleteButton.addTarget(self, action: "deleteText", forControlEvents: .TouchUpInside)
        
        for button in [nextKeyboardButton, menuButton, spaceButton, enterButton, deleteButton] {
            button.sizeToFit()
            button.setTranslatesAutoresizingMaskIntoConstraints(false)
            button.titleLabel?.font = UIFont(name: "HelveticaNeue-Light", size: 18)
            controlViews.addSubview(button)
        }
        
        // layout
        layout(nextKeyboardButton, controlViews) { view1, view2 in
            view1.left == view2.left+10
            view1.centerY == view2.centerY
        }
        
        layout(deleteButton, controlViews) { view1, view2 in
            view1.right == view2.right-10
            view1.centerY == view2.centerY
        }
        
        layout(spaceButton, controlViews) { view1, view2 in
            view1.centerX == view2.centerX
            view1.centerY == view2.centerY
        }

        layout(menuButton, nextKeyboardButton) { view1, view2 in
            view1.left == view2.right + 20
            view1.centerY == view2.centerY
        }
        
        layout(enterButton, deleteButton) { view1, view2 in
            view1.right == view2.left - 20
            view1.centerY == view2.centerY
        }
        

        if isOpenAccessGranted() {
            initializeRealm()
        }
    }
    
    func initializeRealm() {
        
        let directory: NSURL = NSFileManager.defaultManager().containerURLForSecurityApplicationGroupIdentifier(appGroupId)!
        let realmPath = directory.path!.stringByAppendingPathComponent("default.realm")
        Realm.defaultPath = realmPath
        rootCategories = Realm().objects(RootCategory)
        
        // init collection views
        var layout1 = ZLBalancedFlowLayout()
        layout1.headerReferenceSize = CGSizeZero
        layout1.footerReferenceSize = CGSizeZero
        layout1.sectionInset = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
        layout1.rowHeight = 30
        layout1.enforcesRowHeight = true
        layout1.minimumLineSpacing = 0
        layout1.minimumInteritemSpacing = 5
        categoriesCollectionView = UICollectionView(frame: CGRectZero, collectionViewLayout: layout1)
        categoriesCollectionView?.backgroundColor = UIColor.whiteColor()
        categoriesCollectionView?.registerClass(EKCategoryCollectionViewCell.self, forCellWithReuseIdentifier: reuseIdentifier)
        categoriesCollectionView?.registerClass(EKSectionHeaderView.classForCoder(), forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: headerIdentifier)
        categoriesCollectionView?.registerClass(UICollectionReusableView.classForCoder(), forSupplementaryViewOfKind: UICollectionElementKindSectionFooter, withReuseIdentifier: footerIdentifier)
        categoriesCollectionView?.delegate = categoriesCollectionViewDataSourceDelegate
        categoriesCollectionView?.dataSource = categoriesCollectionViewDataSourceDelegate
        
        var layout2 = ZLBalancedFlowLayout()
        layout2.headerReferenceSize = CGSizeZero
        layout2.footerReferenceSize = CGSizeZero
        layout2.sectionInset = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
        layout2.rowHeight = 25
        layout2.enforcesRowHeight = true
        layout2.minimumLineSpacing = 0
        layout2.minimumInteritemSpacing = 5
        emoticonsCollectionView = UICollectionView(frame: CGRectZero, collectionViewLayout: layout2)
        emoticonsCollectionView?.backgroundColor = UIColor.whiteColor()
        emoticonsCollectionView?.registerClass(EKEmoticonCollectionViewCell.self, forCellWithReuseIdentifier: reuseIdentifier)
        emoticonsCollectionView?.delegate = emoticonsCollectionViewDataSourceDelegate
        emoticonsCollectionView?.dataSource = emoticonsCollectionViewDataSourceDelegate
        
        collectionViews.addSubview(emoticonsCollectionView!)
        collectionViews.addSubview(categoriesCollectionView!)
        
        // callbacks
        categoriesCollectionViewDataSourceDelegate.sectionHeaderFontSize = "3em"
        categoriesCollectionViewDataSourceDelegate.didSelectCategory = {category in
            self.currentCategory = category
            self.categoriesCollectionView?.hidden = true
        }
        emoticonsCollectionViewDataSourceDelegate.didSelectEmoticon = {emoticon in
            self.insertText(emoticon.value)
        }
        
        // layout
        
        for collectionView in [categoriesCollectionView!, emoticonsCollectionView!] {
            collectionView.setTranslatesAutoresizingMaskIntoConstraints(false)
            layout(collectionView, collectionViews) { view1, view2 in
                view1.top == view2.top
                view1.bottom == view2.bottom
                view1.left == view2.left
                view1.right == view2.right
            }
            collectionView.reloadData()
        }
        
        // Set realm notification block
        notificationToken = Realm().addNotificationBlock { [unowned self] note, realm in
            self.categoriesCollectionView?.reloadData()
            self.emoticonsCollectionView?.reloadData()
        }
        
    }
    
    func isOpenAccessGranted() -> Bool {
        return UIPasteboard.generalPasteboard().isKindOfClass(UIPasteboard)
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated
    }
    
    // MARK: Actions
    func insertText(text:String) {
        var proxy = self.textDocumentProxy as! UITextDocumentProxy
        proxy.insertText(text)
    }
    func deleteText() {
        var proxy = self.textDocumentProxy as! UITextDocumentProxy
        proxy.deleteBackward()
    }
    func insertSpace() {
        var proxy = self.textDocumentProxy as! UITextDocumentProxy
        proxy.insertText(" ")
    }
    func insertReturn() {
        var proxy = self.textDocumentProxy as! UITextDocumentProxy
        proxy.insertText("\n")
    }
    func showMenu() {
        categoriesCollectionView?.hidden = false
    }

    // MARK: UIInputController
    override func textWillChange(textInput: UITextInput) {
        // The app is about to change the document's contents. Perform any preparation here.
    }

    override func textDidChange(textInput: UITextInput) {
        // The app has just changed the document's contents, the document context has been updated.
    
        var textColor: UIColor
        var proxy = self.textDocumentProxy as! UITextDocumentProxy
        if proxy.keyboardAppearance == UIKeyboardAppearance.Dark {
            textColor = UIColor.whiteColor()
        } else {
            textColor = UIColor.blackColor()
        }
        self.nextKeyboardButton.setTitleColor(textColor, forState: .Normal)
    }

}
<commit_msg>adding timer for delete button<commit_after>//
//  KeyboardViewController.swift
//  Keyboard
//
//  Created by <NAME> on 5/7/15.
//  Copyright (c) 2015 <NAME>. All rights reserved.
//

import UIKit
import RealmSwift
import ZLBalancedFlowLayout
import Cartography
import TTTAttributedLabel
import ReactiveUI

let reuseIdentifier = "Cell", headerIdentifier = "header", footerIdentifier = "footer"
let appGroupId = "group.com.axcel.EmoticonKeyboard"

class KeyboardViewController: UIInputViewController {

    var collectionViews = UIView()
    var controlViews = UIView()

    var nextKeyboardButton: UIButton!
    var menuButton: UIButton!
    var spaceButton: UIButton!
    var enterButton: UIButton!
    var deleteButton: UIButton!
    
    var openAccessLabel = UILabel()

    var categoriesCollectionView: UICollectionView!
    var emoticonsCollectionView: UICollectionView!
    
    var categoriesCollectionViewDataSourceDelegate = EKCategoriesCollectionViewDataSourceDelegate()
    var emoticonsCollectionViewDataSourceDelegate = EKEmoticonsCollectionViewDataSourceDelegate()
    
    var rootCategories : Results<RootCategory>! {
        didSet {
            categoriesCollectionViewDataSourceDelegate.rootCategories = rootCategories
            categoriesCollectionView?.reloadData()
        }
    }
    var currentCategory: Category? {
        didSet {
            emoticonsCollectionViewDataSourceDelegate.category = currentCategory
            emoticonsCollectionView?.reloadData()
        }
    }
    
    var notificationToken: NotificationToken?
    
    // MARK: Input View Constraints
    let portraitHeight = 300, landscapeHeight = 200
    var heightConstraint: NSLayoutConstraint?
    var widthConstraint: NSLayoutConstraint?
    var isProtrait = true
    
    override func updateViewConstraints() {
        super.updateViewConstraints()
        
        // Add custom view sizing constraints here
        updateInputViewConstraints()
    }
    
    override func viewDidLayoutSubviews() {
        view.setNeedsUpdateConstraints()
    }
    
    override func viewDidAppear(animated: Bool) {
        super.viewDidAppear(animated)
        
        if isOpenAccessGranted() {
            openAccessLabel.hidden = true
        } else {
            openAccessLabel.hidden = false
        }
        
        isProtrait = UIScreen.mainScreen().bounds.width < UIScreen.mainScreen().bounds.height
        var height = isProtrait ? portraitHeight : landscapeHeight
        heightConstraint = NSLayoutConstraint(item: view!, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 0, constant: CGFloat(height))
        heightConstraint!.priority = 900
        view.addConstraint(heightConstraint!)
        
        widthConstraint = NSLayoutConstraint(item: view!, attribute: .Width, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 0, constant: UIScreen.mainScreen().bounds.width)
        widthConstraint!.priority = 950
        view.addConstraint(widthConstraint!)
    }
    
    func updateInputViewConstraints() {
        if self.view.frame.size.width == 0 || self.view.frame.size.height == 0 || isProtrait == (UIScreen.mainScreen().bounds.width < UIScreen.mainScreen().bounds.height) {
            return
        }
        if var heightConstraint = heightConstraint, widthConstraint = widthConstraint {
            view!.removeConstraint(heightConstraint)
            isProtrait = UIScreen.mainScreen().bounds.width < UIScreen.mainScreen().bounds.height
            var height = isProtrait ? portraitHeight : landscapeHeight
            self.heightConstraint!.constant = CGFloat(height)
            view!.addConstraint(heightConstraint)
            
            view!.removeConstraint(widthConstraint)
            self.widthConstraint!.constant = UIScreen.mainScreen().bounds.width
            view!.addConstraint(widthConstraint)
        }
    }
    
    // MARK: Life Cycle
    deinit {
        if let notificationToken = notificationToken {
            Realm().removeNotification(notificationToken)
        }
    }
    
    var deleteTimer: NSTimer?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Top level view containers
        for subview in [collectionViews, controlViews, openAccessLabel] {
            subview.setTranslatesAutoresizingMaskIntoConstraints(false)
            view.addSubview(subview)
        }
        view.backgroundColor = UIColor.whiteColor()
        
        openAccessLabel.text = "Please allow full access in Settings > General > Keyboard > Keyboards"
        openAccessLabel.numberOfLines = 0
        openAccessLabel.textColor = UIColor.blackColor()
        openAccessLabel.sizeToFit()
        openAccessLabel.hidden = true
        view.addSubview(openAccessLabel)
        
        view.setTranslatesAutoresizingMaskIntoConstraints(false)
        
        layout(collectionViews, controlViews) { view1, view2 in
            view1.left == view1.superview!.left
            view2.left == view1.left
            view1.right == view1.superview!.right
            view2.right == view1.right
            
            view1.top == view1.superview!.top
            view1.bottom  == view2.top
            view2.bottom == view2.superview!.bottom ~ 100
            view2.height  == 40 ~ 200
        }
        
        layout(openAccessLabel, collectionViews) { view1, view2 in
            view1.centerX == view2.centerX
            view1.centerY == view2.centerY
            view1.left == view1.superview!.left
            view1.right == view1.superview!.right
        }
        
        // Buttons: next menu space return delete
        nextKeyboardButton = UIButton.buttonWithType(.System) as! UIButton
        nextKeyboardButton.setTitle(NSLocalizedString("🌐", comment: "Title for 'Next Keyboard' button"), forState: .Normal)
        nextKeyboardButton.addTarget(self, action: "advanceToNextInputMode", forControlEvents: .TouchUpInside)
        
        menuButton = UIButton.buttonWithType(.System) as! UIButton
        menuButton.setTitle(NSLocalizedString("🚀", comment: "Title for 'Menu' button"), forState: .Normal)
        menuButton.addTarget(self, action: "showMenu", forControlEvents: .TouchUpInside)
        
        spaceButton = UIButton.buttonWithType(.System) as! UIButton
        spaceButton.setTitle(NSLocalizedString("Space", comment: "Title for 'Space' button"), forState: .Normal)
        spaceButton.addTarget(self, action: "insertSpace", forControlEvents: .TouchUpInside)

        enterButton = UIButton.buttonWithType(.System) as! UIButton
        enterButton.setTitle(NSLocalizedString("⏎", comment: "Title for 'Enter' button"), forState: .Normal)
        enterButton.addTarget(self, action: "insertReturn", forControlEvents: .TouchUpInside)
        
        deleteButton = UIButton.buttonWithType(.System) as! UIButton
        deleteButton.setTitle(NSLocalizedString("⌫", comment: "Title for 'Delete' button"), forState: .Normal)
        deleteButton.addAction({button in
            self.deleteText()
            self.deleteTimer = NSTimer.scheduledTimerWithTimeInterval(0.3, action: {timer in
                self.deleteTimer = NSTimer.scheduledTimerWithTimeInterval(0.1, action: {timer in
                    self.deleteText()
                    }, repeats: true)
                }, repeats: false)
            }, forControlEvents: .TouchDown)
        deleteButton.addAction({button in
            self.deleteTimer?.invalidate()
            }, forControlEvents: .TouchUpInside | .TouchUpOutside | .TouchCancel)
        
        for button in [nextKeyboardButton, menuButton, spaceButton, enterButton, deleteButton] {
            button.sizeToFit()
            button.setTranslatesAutoresizingMaskIntoConstraints(false)
            button.titleLabel?.font = UIFont(name: "HelveticaNeue-Light", size: 18)
            controlViews.addSubview(button)
        }
        
        // layout
        layout(nextKeyboardButton, controlViews) { view1, view2 in
            view1.left == view2.left+10
            view1.centerY == view2.centerY
        }
        
        layout(deleteButton, controlViews) { view1, view2 in
            view1.right == view2.right-10
            view1.centerY == view2.centerY
        }
        
        layout(spaceButton, controlViews) { view1, view2 in
            view1.centerX == view2.centerX
            view1.centerY == view2.centerY
        }

        layout(menuButton, nextKeyboardButton) { view1, view2 in
            view1.left == view2.right + 20
            view1.centerY == view2.centerY
        }
        
        layout(enterButton, deleteButton) { view1, view2 in
            view1.right == view2.left - 20
            view1.centerY == view2.centerY
        }
        

        if isOpenAccessGranted() {
            initializeRealm()
        }
    }
    
    func initializeRealm() {
        
        let directory: NSURL = NSFileManager.defaultManager().containerURLForSecurityApplicationGroupIdentifier(appGroupId)!
        let realmPath = directory.path!.stringByAppendingPathComponent("default.realm")
        Realm.defaultPath = realmPath
        rootCategories = Realm().objects(RootCategory)
        
        // init collection views
        var layout1 = ZLBalancedFlowLayout()
        layout1.headerReferenceSize = CGSizeZero
        layout1.footerReferenceSize = CGSizeZero
        layout1.sectionInset = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
        layout1.rowHeight = 30
        layout1.enforcesRowHeight = true
        layout1.minimumLineSpacing = 0
        layout1.minimumInteritemSpacing = 5
        categoriesCollectionView = UICollectionView(frame: CGRectZero, collectionViewLayout: layout1)
        categoriesCollectionView?.backgroundColor = UIColor.whiteColor()
        categoriesCollectionView?.registerClass(EKCategoryCollectionViewCell.self, forCellWithReuseIdentifier: reuseIdentifier)
        categoriesCollectionView?.registerClass(EKSectionHeaderView.classForCoder(), forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: headerIdentifier)
        categoriesCollectionView?.registerClass(UICollectionReusableView.classForCoder(), forSupplementaryViewOfKind: UICollectionElementKindSectionFooter, withReuseIdentifier: footerIdentifier)
        categoriesCollectionView?.delegate = categoriesCollectionViewDataSourceDelegate
        categoriesCollectionView?.dataSource = categoriesCollectionViewDataSourceDelegate
        
        var layout2 = ZLBalancedFlowLayout()
        layout2.headerReferenceSize = CGSizeZero
        layout2.footerReferenceSize = CGSizeZero
        layout2.sectionInset = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
        layout2.rowHeight = 25
        layout2.enforcesRowHeight = true
        layout2.minimumLineSpacing = 0
        layout2.minimumInteritemSpacing = 5
        emoticonsCollectionView = UICollectionView(frame: CGRectZero, collectionViewLayout: layout2)
        emoticonsCollectionView?.backgroundColor = UIColor.whiteColor()
        emoticonsCollectionView?.registerClass(EKEmoticonCollectionViewCell.self, forCellWithReuseIdentifier: reuseIdentifier)
        emoticonsCollectionView?.delegate = emoticonsCollectionViewDataSourceDelegate
        emoticonsCollectionView?.dataSource = emoticonsCollectionViewDataSourceDelegate
        
        collectionViews.addSubview(emoticonsCollectionView!)
        collectionViews.addSubview(categoriesCollectionView!)
        
        // callbacks
        categoriesCollectionViewDataSourceDelegate.sectionHeaderFontSize = "3em"
        categoriesCollectionViewDataSourceDelegate.didSelectCategory = {category in
            self.currentCategory = category
            self.categoriesCollectionView?.hidden = true
        }
        emoticonsCollectionViewDataSourceDelegate.didSelectEmoticon = {emoticon in
            self.insertText(emoticon.value)
        }
        
        // layout
        
        for collectionView in [categoriesCollectionView!, emoticonsCollectionView!] {
            collectionView.setTranslatesAutoresizingMaskIntoConstraints(false)
            layout(collectionView, collectionViews) { view1, view2 in
                view1.top == view2.top
                view1.bottom == view2.bottom
                view1.left == view2.left
                view1.right == view2.right
            }
            collectionView.reloadData()
        }
        
        // Set realm notification block
        notificationToken = Realm().addNotificationBlock { [unowned self] note, realm in
            self.categoriesCollectionView?.reloadData()
            self.emoticonsCollectionView?.reloadData()
        }
        
    }
    
    func isOpenAccessGranted() -> Bool {
        return UIPasteboard.generalPasteboard().isKindOfClass(UIPasteboard)
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated
    }
    
    // MARK: Actions
    func insertText(text:String) {
        var proxy = self.textDocumentProxy as! UITextDocumentProxy
        proxy.insertText(text)
    }
    func deleteText() {
        var proxy = self.textDocumentProxy as! UITextDocumentProxy
        proxy.deleteBackward()
    }
    func insertSpace() {
        var proxy = self.textDocumentProxy as! UITextDocumentProxy
        proxy.insertText(" ")
    }
    func insertReturn() {
        var proxy = self.textDocumentProxy as! UITextDocumentProxy
        proxy.insertText("\n")
    }
    func showMenu() {
        categoriesCollectionView?.hidden = false
    }

    // MARK: UIInputController
    override func textWillChange(textInput: UITextInput) {
        // The app is about to change the document's contents. Perform any preparation here.
    }

    override func textDidChange(textInput: UITextInput) {
        // The app has just changed the document's contents, the document context has been updated.
    
        var textColor: UIColor
        var proxy = self.textDocumentProxy as! UITextDocumentProxy
        if proxy.keyboardAppearance == UIKeyboardAppearance.Dark {
            textColor = UIColor.whiteColor()
        } else {
            textColor = UIColor.blackColor()
        }
        self.nextKeyboardButton.setTitleColor(textColor, forState: .Normal)
    }

}

{'fraction_non_alphanumeric': 0.08022892080193374, 'fraction_numerical': 0.011019479596189393, 'mean_word_length': 2.6876392712019923, 'pattern_counts': {'":': 0, '<': 15, '<?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': '2887101', 'n_tokens_mistral': 7454, 'n_tokens_neox': 7220, 'n_words': 1465}