From 74e2d8d8a7119fceb3f80cd07d4b72597864259b Mon Sep 17 00:00:00 2001 From: Gabriel Wong Date: Fri, 17 Nov 2017 11:41:06 +0700 Subject: [PATCH] Move some view functions out of Manager --- .../Classes/InputViewController.swift | 6 +- .../Classes/KeyboardMenuView.swift | 4 +- .../Classes/KeymanWebViewController.swift | 338 +++++++++++++++ .../KMEI/KeymanEngine/Classes/Manager.swift | 386 +----------------- .../KMEI/KeymanEngine/Classes/TextField.swift | 2 +- .../KMEI/KeymanEngine/Classes/TextView.swift | 2 +- 6 files changed, 362 insertions(+), 376 deletions(-) diff --git a/ios/engine/KMEI/KeymanEngine/Classes/InputViewController.swift b/ios/engine/KMEI/KeymanEngine/Classes/InputViewController.swift index 33f1861665..fd484208aa 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/InputViewController.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/InputViewController.swift @@ -164,7 +164,7 @@ open class InputViewController: UIInputViewController, KeymanWebDelegate { } func insertText(_ keymanWeb: KeymanWebViewController, numCharsToDelete: Int, newText: String) { - if Manager.shared.isSubKeysMenuVisible { + if keymanWeb.isSubKeysMenuVisible { return } @@ -202,7 +202,7 @@ open class InputViewController: UIInputViewController, KeymanWebDelegate { } func menuKeyUp(_ keymanWeb: KeymanWebViewController) { - if Manager.shared.isKeyboardMenuVisible { + if keymanWeb.isKeyboardMenuVisible { return } @@ -222,7 +222,7 @@ open class InputViewController: UIInputViewController, KeymanWebDelegate { switch menuBehaviour { case .showAlways, .showIfMultipleKeyboards where keyboardListCount > 1: - Manager.shared.showKeyboardMenu(self, closeButtonTitle: menuCloseButtonTitle) + keymanWeb.showKeyboardMenu(self, closeButtonTitle: menuCloseButtonTitle) case .showIfMultipleKeyboards, // keyboardListCount() <= 1 .showNever: break diff --git a/ios/engine/KMEI/KeymanEngine/Classes/KeyboardMenuView.swift b/ios/engine/KMEI/KeymanEngine/Classes/KeyboardMenuView.swift index caa0def4f0..afe0996cf6 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/KeyboardMenuView.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/KeyboardMenuView.swift @@ -239,7 +239,7 @@ class KeyboardMenuView: UIView, UITableViewDelegate, UITableViewDataSource, UIGe } @objc func tapAction(_ sender: UITapGestureRecognizer) { - Manager.shared.dismissKeyboardMenu() + Manager.shared.keymanWeb.dismissKeyboardMenu() } func numberOfSections(in tableView: UITableView) -> Int { @@ -297,7 +297,7 @@ class KeyboardMenuView: UIView, UITableViewDelegate, UITableViewDataSource, UIGe func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { switchKeyboard(indexPath.row) - Manager.shared.dismissKeyboardMenu() + Manager.shared.keymanWeb.dismissKeyboardMenu() } func getMaxWidth() -> CGFloat { diff --git a/ios/engine/KMEI/KeymanEngine/Classes/KeymanWebViewController.swift b/ios/engine/KMEI/KeymanEngine/Classes/KeymanWebViewController.swift index 958c9a7ece..cabbf81493 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/KeymanWebViewController.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/KeymanWebViewController.swift @@ -9,10 +9,29 @@ import UIKit import WebKit +private let keyboardChangeHelpText = "Tap here to change keyboard" + +private let subKeyColor = #colorLiteral(red: 244.0 / 255.0, green: 244.0 / 255.0, blue: 244.0 / 255.0, alpha: 1.0) +private let subKeyColorHighlighted = #colorLiteral(red: 136.0 / 255.0, green: 136.0 / 255.0, blue: 1.0, alpha: 1.0) + // MARK: - UIViewController class KeymanWebViewController: UIViewController { weak var delegate: KeymanWebDelegate? + private var useSpecialFont = false + + // Views var webView: WKWebView! + private var helpBubbleView: PopoverView? + private var keyPreviewView: KeyPreviewView? + private var subKeysView: SubKeysView? + private var keyboardMenuView: KeyboardMenuView? + + // Arrays + private var subKeyIDs: [String] = [] + private var subKeyTexts: [String] = [] + private var subKeys: [UIButton] = [] + + private var subKeyAnchor = CGRect.zero var frame: CGRect? { didSet(frame) { @@ -41,6 +60,11 @@ class KeymanWebViewController: UIViewController { view = webView + // Set UILongPressGestureRecognizer to show sub keys + let hold = UILongPressGestureRecognizer(target: self, action: #selector(self.holdAction)) + hold.minimumPressDuration = 0.5 + hold.delegate = self + view.addGestureRecognizer(hold) reloadKeyboard() } @@ -269,9 +293,192 @@ extension KeymanWebViewController: WKNavigationDelegate { // MARK: - KeymanWebDelegate extension KeymanWebViewController: KeymanWebDelegate { + func insertText(_ view: KeymanWebViewController, numCharsToDelete: Int, newText: String) { + dismissHelpBubble() + Manager.shared.isKeymanHelpOn = false + } + func showKeyPreview(_ view: KeymanWebViewController, keyFrame: CGRect, preview: String) { + if UIDevice.current.userInterfaceIdiom == .pad + || (Util.isSystemKeyboard && !Manager.shared.isSystemKeyboardTopBarEnabled) + || isSubKeysMenuVisible { + return + } + + dismissKeyPreview() + clearSubKeyArrays() + + keyPreviewView = KeyPreviewView(frame: keyFrame) + + keyPreviewView!.setLabelText(preview) + let keyboardID = Manager.shared.keyboardID! + let languageID = Manager.shared.languageID! + var oskFontName = Manager.shared.oskFontNameForKeyboard(withID: keyboardID, languageID: languageID) + oskFontName = oskFontName ?? Manager.shared.fontNameForKeyboard(withID: keyboardID, languageID: languageID) + keyPreviewView!.setLabelFont(oskFontName) + self.view.addSubview(keyPreviewView!) + } + + func dismissKeyPreview(_ view: KeymanWebViewController) { + if UIDevice.current.userInterfaceIdiom == .pad || keyPreviewView == nil { + return + } + + let dismissKeyPreview = #selector(self.dismissKeyPreview as () -> Void) + NSObject.cancelPreviousPerformRequests(withTarget: self, selector: dismissKeyPreview, object: nil) + perform(dismissKeyPreview, with: nil, afterDelay: 0.1) + clearSubKeyArrays() + } + + func showSubkeys(_ view: KeymanWebViewController, + keyFrame: CGRect, + subkeyIDs: [String], + subkeyTexts: [String], + useSpecialFont: Bool) { + dismissHelpBubble() + Manager.shared.isKeymanHelpOn = false + dismissSubKeys() + dismissKeyboardMenu() + + subKeyAnchor = keyFrame + subKeyIDs = subkeyIDs + subKeyTexts = subkeyTexts + self.useSpecialFont = useSpecialFont + } + + func menuKeyUp(_ view: KeymanWebViewController) { + dismissHelpBubble() + Manager.shared.isKeymanHelpOn = false + if Util.isSystemKeyboard { + let userData = UserDefaults.standard + userData.set(true, forKey: Key.keyboardPickerDisplayed) + userData.synchronize() + } + } + + func hideKeyboard(_ view: KeymanWebViewController) { + dismissHelpBubble() + dismissSubKeys() + dismissKeyboardMenu() + } } +// MARK: - UIGestureRecognizerDelegate +extension KeymanWebViewController: UIGestureRecognizerDelegate { + // UILongPressGestureRecognizer implementation to show sub keys in a subview + @objc func holdAction(_ sender: UILongPressGestureRecognizer) { + switch sender.state { + case .ended: + // Touch Ended + if let subKeysView = subKeysView { + subKeysView.removeFromSuperview() + subKeysView.subviews.forEach { $0.removeFromSuperview() } + self.subKeysView = nil + setPopupVisible(false) + } + var buttonClicked = false + for button in subKeys where button.isHighlighted { + button.isHighlighted = false + button.backgroundColor = subKeyColor + button.isEnabled = false + button.sendActions(for: .touchUpInside) + buttonClicked = true + break + } + if !buttonClicked { + clearSubKeyArrays() + } + case .began: + // Touch & Hold Began + let touchPoint = sender.location(in: sender.view) + // Check if touch was for language menu button + languageMenuPosition { keyFrame in + if keyFrame.contains(touchPoint) { + self.delegate?.menuKeyHeld(self) + return + } + self.touchHoldBegan() + } + default: + // Hold & Move + guard let subKeysView = subKeysView else { + return + } + let touchPoint = sender.location(in: subKeysView.containerView) + for button in subKeys { + if button.frame.contains(touchPoint) { + button.isEnabled = true + button.isHighlighted = true + button.backgroundColor = subKeyColorHighlighted + } else { + button.isHighlighted = false + button.isEnabled = false + button.backgroundColor = subKeyColor + } + } + } + } + + private func touchHoldBegan() { + let isPad = UIDevice.current.userInterfaceIdiom == .pad + let fontSize = isPad ? UIFont.buttonFontSize * 2 : UIFont.buttonFontSize + + let keyboardID = Manager.shared.keyboardID! + let languageID = Manager.shared.languageID! + let oskFontName = Manager.shared.oskFontNameForKeyboard(withID: keyboardID, languageID: languageID) + ?? Manager.shared.fontNameForKeyboard(withID: keyboardID, languageID: languageID) + + if subKeyIDs.isEmpty { + subKeys = [] + return + } + + subKeys = subKeyTexts.enumerated().map { i, subKeyText in + let button = UIButton(type: .custom) + button.tag = i + button.backgroundColor = subKeyColor + button.setRoundedBorder(withRadius: 4.0, borderWidth: 1.0, color: .gray) + button.setTitleColor(.black, for: .disabled) + button.setTitleColor(.black, for: .highlighted) + + if let oskFontName = oskFontName { + button.titleLabel?.font = UIFont(name: oskFontName, size: fontSize) + } else { + button.titleLabel?.font = UIFont.systemFont(ofSize: fontSize) + } + + if useSpecialFont { + button.titleLabel?.font = UIFont(name: "KeymanwebOsk", size: fontSize) + button.setTitleColor(.gray, for: .disabled) + } + + button.addTarget(self, action: #selector(subKeyButtonClick), for: .touchUpInside) + button.setTitle(subKeyText, for: .normal) + button.tintColor = UIColor(red: 181.0 / 255.0, green: 181.0 / 255.0, blue: 181.0 / 255.0, alpha: 1.0) + button.isEnabled = false + return button + } + + dismissKeyPreview() + subKeysView = SubKeysView(keyFrame: subKeyAnchor, subKeys: subKeys) + view.addSubview(subKeysView!) + setPopupVisible(true) + } + + @objc func subKeyButtonClick(_ sender: UIButton) { + let keyIndex = sender.tag + if keyIndex < subKeyIDs.count && keyIndex < subKeyTexts.count { + let subKeyID = subKeyIDs[keyIndex] + let subKeyText = subKeyTexts[keyIndex] + executePopupKey(id: subKeyID, text: subKeyText) + } + subKeys.removeAll() + subKeyIDs.removeAll() + subKeyTexts.removeAll() + } +} + +// MARK: - Manage views extension KeymanWebViewController { func reloadKeyboard() { if #available(iOS 9.0, *) { @@ -285,4 +492,135 @@ extension KeymanWebViewController { } } + @objc func showHelpBubble() { + // Help bubble is always disabled for system-wide keyboard + if Util.isSystemKeyboard || keyboardMenuView != nil { + return + } + + languageMenuPosition { keyFrame in + self.showHelpBubble(at: keyFrame.origin) + } + } + + // TODO: The bulk of this should be moved to PopoverView + private func showHelpBubble(at point: CGPoint) { + self.helpBubbleView?.removeFromSuperview() + let helpBubbleView = PopoverView(frame: CGRect.zero) + self.helpBubbleView = helpBubbleView + helpBubbleView.backgroundColor = UIColor(red: 253.0 / 255.0, green: 244.0 / 255.0, + blue: 196.0 / 255.0, alpha: 1.0) + helpBubbleView.backgroundColor2 = UIColor(red: 233.0 / 255.0, green: 224.0 / 255.0, + blue: 176.0 / 255.0, alpha: 1.0) + helpBubbleView.borderColor = UIColor(red: 0.5, green: 0.25, blue: 0.25, alpha: 1.0) + + let isPad = UIDevice.current.userInterfaceIdiom == .pad + let sizeMultiplier = CGFloat(isPad ? 1.5 : 1.0) + let frameWidth = 90.0 * sizeMultiplier + let frameHeight = (40.0 + helpBubbleView.arrowHeight) * sizeMultiplier + let fontSize = 10.0 * sizeMultiplier + + let inputViewFrame = view.frame + let screenWidth = inputViewFrame.size.width + + // TODO: Refactor this out + let isPortrait = UIDevice.current.orientation.isPortrait + + let adjY: CGFloat + if isPortrait { + adjY = Util.isSystemKeyboard ? 9.0 : 4.0 + } else { + adjY = Util.isSystemKeyboard ? 3.0 : 4.0 + } + let px = point.x + let py = point.y + adjY + (isPad ? 2.0 : 1.0) + var x = px - frameWidth / 2 + let y = py - frameHeight + if x < 0 { + x = 0 + } else if x + frameWidth > screenWidth { + x = screenWidth - frameWidth + } + + helpBubbleView.frame = CGRect(x: x, y: y, width: frameWidth, height: frameHeight) + if x == 0 { + helpBubbleView.arrowPosX = px + } else if x == screenWidth - frameWidth { + helpBubbleView.arrowPosX = (px - x) + } else { + helpBubbleView.arrowPosX = frameWidth / 2 + } + + let helpText = UILabel(frame: CGRect(x: 5, y: 0, + width: frameWidth - 10, height: frameHeight - helpBubbleView.arrowHeight)) + helpText.backgroundColor = UIColor.clear + helpText.font = helpText.font.withSize(fontSize) + helpText.textAlignment = .center + helpText.textColor = UIColor.darkText + helpText.lineBreakMode = .byWordWrapping + helpText.numberOfLines = 0 + helpText.text = keyboardChangeHelpText + helpBubbleView.addSubview(helpText) + view.addSubview(helpBubbleView) + } + + func dismissHelpBubble() { + helpBubbleView?.removeFromSuperview() + helpBubbleView = nil + } + + @objc func dismissKeyPreview() { + keyPreviewView?.removeFromSuperview() + keyPreviewView = nil + } + + var isSubKeysMenuVisible: Bool { + return subKeysView != nil + } + + func dismissSubKeys() { + if let subKeysView = subKeysView { + subKeysView.removeFromSuperview() + subKeysView.subviews.forEach { $0.removeFromSuperview() } + self.subKeysView = nil + setPopupVisible(false) + } + clearSubKeyArrays() + } + + func clearSubKeyArrays() { + if subKeysView == nil { + subKeys.removeAll() + subKeyIDs.removeAll() + subKeyTexts.removeAll() + } + } + + func showHelpBubble(afterDelay delay: TimeInterval) { + helpBubbleView?.removeFromSuperview() + let showHelpBubble = #selector(self.showHelpBubble as () -> Void) + NSObject.cancelPreviousPerformRequests(withTarget: self, selector: showHelpBubble, object: nil) + perform(showHelpBubble, with: nil, afterDelay: delay) + } + + func showKeyboardMenu(_ ic: InputViewController, closeButtonTitle: String?) { + let parentView = ic.view ?? view + languageMenuPosition { keyFrame in + if keyFrame != .zero { + self.keyboardMenuView?.removeFromSuperview() + self.keyboardMenuView = KeyboardMenuView(keyFrame: keyFrame, inputViewController: ic, + closeButtonTitle: closeButtonTitle) + parentView?.addSubview(self.keyboardMenuView!) + } + } + } + + func dismissKeyboardMenu() { + keyboardMenuView?.removeFromSuperview() + keyboardMenuView = nil + } + + var isKeyboardMenuVisible: Bool { + return keyboardMenuView != nil + } } diff --git a/ios/engine/KMEI/KeymanEngine/Classes/Manager.swift b/ios/engine/KMEI/KeymanEngine/Classes/Manager.swift index f39332107b..fca37fbe23 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/Manager.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/Manager.swift @@ -22,12 +22,7 @@ public enum KeyboardState { case none } -// Strings -private let keyboardChangeHelpText = "Tap here to change keyboard" - // URLs -private let apiBaseURL = "https://r.keymanweb.com/api/4.0/" -private let apiRemoteURL = "https://r.keymanweb.com/api/2.0/remote?url=" private let keymanHostName = "r.keymanweb.com" // UI In-App Keyboard Constants @@ -100,13 +95,6 @@ public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegat let kmw = KeymanWebViewController(nibName: nil, bundle: nil) kmw.frame = CGRect(origin: .zero, size: keyboardSize) kmw.delegate = self - - // Set UILongPressGestureRecognizer to show sub keys - // TODO: Move to KeymanWebViewController - let hold = UILongPressGestureRecognizer(target: self, action: #selector(self.holdAction)) - hold.minimumPressDuration = 0.5 - hold.delegate = self - kmw.view.addGestureRecognizer(hold) return kmw }() @@ -116,25 +104,6 @@ public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegat private var didSynchronize = false private var didResizeToOrientation = false private var lastKeyboardSize: CGSize = .zero - private var specialOSKFont: String? - - private let subKeyColor = #colorLiteral(red: 244.0 / 255.0, green: 244.0 / 255.0, blue: 244.0 / 255.0, alpha: 1.0) - private let subKeyColorHighlighted = #colorLiteral(red: 136.0 / 255.0, green: 136.0 / 255.0, blue: 1.0, alpha: 1.0) - - // Views - private var helpBubbleView: PopoverView? - private var keyPreviewView: KeyPreviewView? - private var subKeysView: SubKeysView? - private var keyboardMenuView: KeyboardMenuView? - - // Arrays - private var subKeyIDs: [String] = [] - private var subKeyTexts: [String] = [] - private var subKeys: [UIButton] = [] - - // Key frames - private var keyFrame = CGRect.zero - private var menuKeyFrame = CGRect.zero // MARK: - Object Admin deinit { @@ -263,10 +232,7 @@ public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegat userData.synchronize() if isKeymanHelpOn { - helpBubbleView?.removeFromSuperview() - let showHelpBubble = #selector(self.showHelpBubble as () -> Void) - NSObject.cancelPreviousPerformRequests(withTarget: self, selector: showHelpBubble, object: nil) - perform(showHelpBubble, with: nil, afterDelay: 1.5) + keymanWeb.showHelpBubble(afterDelay: 1.5) } NotificationCenter.default.post(name: Notifications.keyboardChanged, @@ -936,48 +902,6 @@ public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegat keymanWeb.setOskHeight(oskHeight) } - private var keymanScrollView: UIScrollView { - return keymanWeb.webView.scrollView - } - - @objc func clearSubKeyArrays() { - if subKeysView == nil { - subKeys.removeAll() - subKeyIDs.removeAll() - subKeyTexts.removeAll() - } - } - - @objc func dismissHelpBubble() { - if let view = helpBubbleView { - view.removeFromSuperview() - helpBubbleView = nil - } - } - - @objc func dismissKeyPreview() { - if let view = keyPreviewView { - view.removeFromSuperview() - keyPreviewView = nil - } - } - - var isSubKeysMenuVisible: Bool { - return subKeysView != nil - } - - private func dismissSubKeys() { - if let subKeysView = subKeysView { - subKeysView.removeFromSuperview() - subKeysView.subviews.forEach { $0.removeFromSuperview() } - self.subKeysView = nil - keymanWeb.setPopupVisible(false) - } - subKeys.removeAll() - subKeyIDs.removeAll() - subKeyTexts.removeAll() - } - /// Displays a list of available keyboards and allows a user to add/download new keyboards /// or remove existing ones. /// @@ -1025,83 +949,6 @@ public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegat } } - @objc func showHelpBubble() { - // Help bubble is always disabled for system-wide keyboard - if Util.isSystemKeyboard || keyboardMenuView != nil { - return - } - - keymanWeb.languageMenuPosition { keyFrame in - self.showHelpBubble(at: keyFrame.origin) - } - } - - // TODO: The bulk of this should be moved to PopoverView - func showHelpBubble(at point: CGPoint) { - self.helpBubbleView?.removeFromSuperview() - let helpBubbleView = PopoverView(frame: CGRect.zero) - self.helpBubbleView = helpBubbleView - helpBubbleView.backgroundColor = UIColor(red: 253.0 / 255.0, green: 244.0 / 255.0, - blue: 196.0 / 255.0, alpha: 1.0) - helpBubbleView.backgroundColor2 = UIColor(red: 233.0 / 255.0, green: 224.0 / 255.0, - blue: 176.0 / 255.0, alpha: 1.0) - helpBubbleView.borderColor = UIColor(red: 0.5, green: 0.25, blue: 0.25, alpha: 1.0) - - let isPad = UIDevice.current.userInterfaceIdiom == .pad - let sizeMultiplier = CGFloat(isPad ? 1.5 : 1.0) - let frameWidth = 90.0 * sizeMultiplier - let frameHeight = (40.0 + helpBubbleView.arrowHeight) * sizeMultiplier - let fontSize = 10.0 * sizeMultiplier - - let inputViewFrame = keymanWeb.view.frame - let screenWidth = inputViewFrame.size.width - - // TODO: Refactor this out - let isPortrait: Bool - if Util.isSystemKeyboard { - isPortrait = InputViewController.isPortrait - } else { - isPortrait = UIDevice.current.orientation.isPortrait - } - - let adjY: CGFloat - if isPortrait { - adjY = Util.isSystemKeyboard ? 9.0 : 4.0 - } else { - adjY = Util.isSystemKeyboard ? 3.0 : 4.0 - } - let px = point.x - let py = point.y + adjY + (isPad ? 2.0 : 1.0) - var x = px - frameWidth / 2 - let y = py - frameHeight - if x < 0 { - x = 0 - } else if x + frameWidth > screenWidth { - x = screenWidth - frameWidth - } - - helpBubbleView.frame = CGRect(x: x, y: y, width: frameWidth, height: frameHeight) - if x == 0 { - helpBubbleView.arrowPosX = px - } else if x == screenWidth - frameWidth { - helpBubbleView.arrowPosX = (px - x) - } else { - helpBubbleView.arrowPosX = frameWidth / 2 - } - - let helpText = UILabel(frame: CGRect(x: 5, y: 0, - width: frameWidth - 10, height: frameHeight - helpBubbleView.arrowHeight)) - helpText.backgroundColor = UIColor.clear - helpText.font = helpText.font.withSize(fontSize) - helpText.textAlignment = .center - helpText.textColor = UIColor.darkText - helpText.lineBreakMode = .byWordWrapping - helpText.numberOfLines = 0 - helpText.text = keyboardChangeHelpText - helpBubbleView.addSubview(helpText) - keymanWeb.view.addSubview(helpBubbleView) - } - @objc func resizeDelay() { // + 1000 to work around iOS bug with resizing on landscape orientation. Technically we only // need this for landscape but it doesn't hurt to do it with both. 1000 is a big number that @@ -1155,22 +1002,19 @@ public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegat // MARK: - Keyboard Notifications @objc func keyboardWillShow(_ notification: Notification) { - dismissSubKeys() - dismissKeyPreview() + keymanWeb.dismissSubKeys() + keymanWeb.dismissKeyPreview() resizeKeyboard() if isKeymanHelpOn { - helpBubbleView?.removeFromSuperview() - let showHelpBubble = #selector(self.showHelpBubble as () -> Void) - NSObject.cancelPreviousPerformRequests(withTarget: self, selector: showHelpBubble, object: nil) - perform(showHelpBubble, with: nil, afterDelay: 1.5) + keymanWeb.showHelpBubble(afterDelay: 1.5) } } @objc func keyboardWillHide(_ notification: Notification) { - dismissHelpBubble() - dismissSubKeys() - dismissKeyPreview() + keymanWeb.dismissHelpBubble() + keymanWeb.dismissSubKeys() + keymanWeb.dismissKeyPreview() } // MARK: - KeymanWebViewDelegate methods @@ -1206,43 +1050,14 @@ public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegat func insertText(_ keymanWeb: KeymanWebViewController, numCharsToDelete: Int, newText: String) { keymanWebDelegate?.insertText(keymanWeb, numCharsToDelete: numCharsToDelete, newText: newText) - - dismissHelpBubble() - isKeymanHelpOn = false } func showKeyPreview(_ keymanWeb: KeymanWebViewController, keyFrame: CGRect, preview: String) { keymanWebDelegate?.showKeyPreview(keymanWeb, keyFrame: keyFrame, preview: preview) - - if UIDevice.current.userInterfaceIdiom == .pad - || (Util.isSystemKeyboard && !isSystemKeyboardTopBarEnabled) - || subKeysView != nil { - return - } - - dismissKeyPreview() - clearSubKeyArrays() - - keyPreviewView = KeyPreviewView(frame: keyFrame) - - keyPreviewView!.setLabelText(preview) - var oskFontName = oskFontNameForKeyboard(withID: keyboardID!, languageID: languageID!) - oskFontName = oskFontName ?? fontNameForKeyboard(withID: keyboardID!, languageID: languageID!) - keyPreviewView!.setLabelFont(oskFontName) - keymanWeb.view.addSubview(keyPreviewView!) } func dismissKeyPreview(_ keymanWeb: KeymanWebViewController) { keymanWebDelegate?.dismissKeyPreview(keymanWeb) - - if UIDevice.current.userInterfaceIdiom == .pad || keyPreviewView == nil { - return - } - - let dismissKeyPreview = #selector(self.dismissKeyPreview as () -> Void) - NSObject.cancelPreviousPerformRequests(withTarget: self, selector: dismissKeyPreview, object: nil) - perform(dismissKeyPreview, with: nil, afterDelay: 0.1) - clearSubKeyArrays() } func showSubkeys(_ keymanWeb: KeymanWebViewController, @@ -1255,15 +1070,6 @@ public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegat subkeyIDs: subkeyIDs, subkeyTexts: subkeyTexts, useSpecialFont: useSpecialFont) - - dismissHelpBubble() - isKeymanHelpOn = false - dismissSubKeys() - dismissKeyboardMenu() - - self.keyFrame = keyFrame - subKeyIDs = subkeyIDs - subKeyTexts = subkeyTexts } func menuKeyDown(_ keymanWeb: KeymanWebViewController) { @@ -1272,156 +1078,25 @@ public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegat func menuKeyUp(_ keymanWeb: KeymanWebViewController) { keymanWebDelegate?.menuKeyUp(keymanWeb) - - dismissHelpBubble() - isKeymanHelpOn = false - if Util.isSystemKeyboard { - let userData = UserDefaults.standard - userData.set(true, forKey: Key.keyboardPickerDisplayed) - userData.synchronize() - } } func hideKeyboard(_ keymanWeb: KeymanWebViewController) { keymanWebDelegate?.hideKeyboard(keymanWeb) - - dismissHelpBubble() - dismissSubKeys() - dismissKeyboardMenu() - } - - // MARK: - UIGestureRecognizer - public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, - shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool { - return true - } - - // UILongPressGestureRecognizer implementation to show sub keys in a subview - @objc func holdAction(_ sender: UILongPressGestureRecognizer) { - switch sender.state { - case .ended: - // Touch Ended - if let subKeysView = subKeysView { - subKeysView.removeFromSuperview() - subKeysView.subviews.forEach { $0.removeFromSuperview() } - self.subKeysView = nil - keymanWeb.setPopupVisible(false) - } - var buttonClicked = false - for button in subKeys where button.isHighlighted { - button.isHighlighted = false - button.backgroundColor = subKeyColor - button.isEnabled = false - button.sendActions(for: .touchUpInside) - buttonClicked = true - break - } - if !buttonClicked { - clearSubKeyArrays() - } - case .began: - // Touch & Hold Began - let touchPoint = sender.location(in: sender.view) - // Check if touch was for language menu button - keymanWeb.languageMenuPosition { keyFrame in - self.menuKeyFrame = keyFrame - if keyFrame.contains(touchPoint) { - self.keymanWebDelegate?.menuKeyHeld(self.keymanWeb) - return - } - self.touchHoldBegan() - } - default: - // Hold & Move - guard let subKeysView = subKeysView else { - return - } - let touchPoint = sender.location(in: subKeysView.containerView) - for button in subKeys { - if button.frame.contains(touchPoint) { - button.isEnabled = true - button.isHighlighted = true - button.backgroundColor = subKeyColorHighlighted - } else { - button.isHighlighted = false - button.isEnabled = false - button.backgroundColor = subKeyColor - } - } - } - } - - private func touchHoldBegan() { - let isPad = UIDevice.current.userInterfaceIdiom == .pad - let fontSize = isPad ? UIFont.buttonFontSize * 2 : UIFont.buttonFontSize - - var oskFontName = oskFontNameForKeyboard(withID: keyboardID!, languageID: languageID!) - if oskFontName == nil { - oskFontName = fontNameForKeyboard(withID: keyboardID!, languageID: languageID!) - } - - if subKeyIDs.isEmpty { - subKeys = [] - return - } - - subKeys = subKeyTexts.enumerated().map { i, subKeyText in - let button = UIButton(type: .custom) - button.tag = i - button.backgroundColor = subKeyColor - button.setRoundedBorder(withRadius: 4.0, borderWidth: 1.0, color: .gray) - button.setTitleColor(.black, for: .disabled) - button.setTitleColor(.black, for: .highlighted) - - if let oskFontName = oskFontName { - button.titleLabel?.font = UIFont(name: oskFontName, size: fontSize) - } else { - button.titleLabel?.font = UIFont.systemFont(ofSize: fontSize) - } - - if specialOSKFont != nil { - button.titleLabel?.font = UIFont(name: "KeymanwebOsk", size: fontSize) - button.setTitleColor(.gray, for: .disabled) - } - - button.addTarget(self, action: #selector(subKeyButtonClick), for: .touchUpInside) - button.setTitle(subKeyText, for: .normal) - button.tintColor = UIColor(red: 181.0 / 255.0, green: 181.0 / 255.0, blue: 181.0 / 255.0, alpha: 1.0) - button.isEnabled = false - return button - } - - dismissKeyPreview() - subKeysView = SubKeysView(keyFrame: keyFrame, subKeys: subKeys) - keymanWeb.view.addSubview(subKeysView!) - keymanWeb.setPopupVisible(true) - } - - @objc func subKeyButtonClick(_ sender: UIButton) { - let keyIndex = sender.tag - if keyIndex < subKeyIDs.count && keyIndex < subKeyTexts.count { - let subKeyID = subKeyIDs[keyIndex] - let subKeyText = subKeyTexts[keyIndex] - keymanWeb.executePopupKey(id: subKeyID, text: subKeyText) - } - subKeys.removeAll() - subKeyIDs.removeAll() - subKeyTexts.removeAll() } // MARK: - InputViewController methods // TODO: Manager should not have InputViewController methods. Move this into InputViewController. func updateViewConstraints() { - dismissSubKeys() - dismissKeyPreview() - dismissKeyboardMenu() + keymanWeb.dismissSubKeys() + keymanWeb.dismissKeyPreview() + keymanWeb.dismissKeyboardMenu() resizeKeyboardIfNeeded() } func inputViewDidLoad() { - dismissSubKeys() - dismissKeyPreview() - dismissKeyboardMenu() + keymanWeb.dismissSubKeys() + keymanWeb.dismissKeyPreview() + keymanWeb.dismissKeyboardMenu() resizeKeyboard() let activeUserDef = Storage.active.userDefaults @@ -1454,43 +1129,16 @@ public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegat // FIXME: This is deprecated. Use inputViewWillTransition() func inputViewWillRotate(to toInterfaceOrientation: UIInterfaceOrientation, duration: TimeInterval) { - dismissSubKeys() - dismissKeyPreview() - dismissKeyboardMenu() + keymanWeb.dismissSubKeys() + keymanWeb.dismissKeyPreview() + keymanWeb.dismissKeyboardMenu() resizeKeyboard(with: toInterfaceOrientation) if isKeymanHelpOn { - helpBubbleView?.removeFromSuperview() - let showHelpBubble = #selector(self.showHelpBubble as () -> Void) - NSObject.cancelPreviousPerformRequests(withTarget: self, selector: showHelpBubble, object: nil) - perform(showHelpBubble, with: nil, afterDelay: 1.5) + keymanWeb.showHelpBubble(afterDelay: 1.5) } didResizeToOrientation = true } - func showKeyboardMenu(_ ic: InputViewController, closeButtonTitle: String?) { - let parentView = ic.view ?? keymanWeb.view - keymanWeb.languageMenuPosition { keyFrame in - self.menuKeyFrame = keyFrame - if keyFrame != .zero { - self.keyboardMenuView?.removeFromSuperview() - self.keyboardMenuView = KeyboardMenuView(keyFrame: self.menuKeyFrame, inputViewController: ic, - closeButtonTitle: closeButtonTitle) - parentView?.addSubview(self.keyboardMenuView!) - } - } - } - - func dismissKeyboardMenu() { - if let keyboardMenuView = keyboardMenuView { - keyboardMenuView.removeFromSuperview() - self.keyboardMenuView = nil - } - } - - var isKeyboardMenuVisible: Bool { - return keyboardMenuView != nil - } - var isSystemKeyboardTopBarEnabled: Bool { return true } diff --git a/ios/engine/KMEI/KeymanEngine/Classes/TextField.swift b/ios/engine/KMEI/KeymanEngine/Classes/TextField.swift index 9f01e4f89c..d3e627c672 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/TextField.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/TextField.swift @@ -187,7 +187,7 @@ public class TextField: UITextField { // MARK: - KeymanWebDelegate extension TextField: KeymanWebDelegate { func insertText(_ keymanWeb: KeymanWebViewController, numCharsToDelete: Int, newText: String) { - if Manager.shared.isSubKeysMenuVisible { + if keymanWeb.isSubKeysMenuVisible { return } diff --git a/ios/engine/KMEI/KeymanEngine/Classes/TextView.swift b/ios/engine/KMEI/KeymanEngine/Classes/TextView.swift index 742849181f..b18bc9f886 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/TextView.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/TextView.swift @@ -188,7 +188,7 @@ public class TextView: UITextView { // MARK: - KeymanWebDelegate extension TextView: KeymanWebDelegate { func insertText(_ keymanWeb: KeymanWebViewController, numCharsToDelete: Int, newText: String) { - if Manager.shared.isSubKeysMenuVisible { + if keymanWeb.isSubKeysMenuVisible { return }