How to choose the background keyboard? - swift

I work on a custom keyboard (My Keyboard is no xib or StoryBoard),
I want to know if I can choose the background to remain constant
according to the choice The custom keyboard on
For example: When I choose the keyboard to keyboard Dark then stay in the selected mode "Dark".
And when I want to change the background again to be in the Light then again to stay in the selected mode "Light".
This would look like:
KeyboardInputTraits.swift
func pollTraits() {
if let proxy = (self.textDocumentProxy as? UITextInputTraits) {
if let layout = self.layout {
let appearanceIsDark = (proxy.keyboardAppearance == UIKeyboardAppearance.Dark)
if appearanceIsDark != layout.darkMode {
self.updateAppearances(appearanceIsDark)
}
}
}
}
KeyboardViewController.swift
func darkMode() -> Bool {
var darkMode = { () -> Bool in
if let proxy = self.textDocumentProxy as? UITextDocumentProxy {
return proxy.keyboardAppearance == UIKeyboardAppearance.Dark
}
else {
return false
}
}()
return darkMode
}

Related

Password Validation based on image Changes in swift

Hi Good morning every one please any one to solve this issues
I had 4 images one password filed
here when user enter capital and small letter and I need to tick one image
again user enter enter number in textfield I need to tick another image
again user enter special character I need to tick another image
if user remove character based on that I need to deselect the image any one help to solve this issues
here is my code
#IBAction func textFieldEditingChanged(_ sender: Any) {
viewPasswordStrength.isHidden = false
if isValidated(passwordTextField.text!){
print("succ")
}
}
func isValidated(_ password: String) -> Bool {
var lowerCaseLetter: Bool = false
var upperCaseLetter: Bool = false
var digit: Bool = false
var specialCharacter: Bool = false
for char in password.unicodeScalars {
if !lowerCaseLetter {
lowerCaseLetter = CharacterSet.lowercaseLetters.contains(char)
}
if !upperCaseLetter {
upperCaseLetter = CharacterSet.uppercaseLetters.contains(char)
}
if !digit {
digit = CharacterSet.decimalDigits.contains(char)
}
if !specialCharacter {
specialCharacter = CharacterSet.punctuationCharacters.contains(char)
}
}
if ( lowerCaseLetter && upperCaseLetter) {
//do what u want
self.UpperCaseImageConditions_img.image = UIImage(named: "GreenTick")
return true
}
if (specialCharacter) {
//do what u want
self.SpecialCharacter_img.image = UIImage(named: "GreenTick")
return true
}
if ( digit) {
//do what u want
self.onenumberImageCondiotion_img.image = UIImage(named: "GreenTick")
return true
}
else {
self.UpperCaseImageConditions_img.image = UIImage(named: "redtick")
return false
}
}
here I cannot change the image based on the user enter the text in password filed
THANKS IN ADVANCE

NScrollView in NSPopover autolayout issue

I have an NSPopover which contains an NSViewController with a containing NSScrollView.
The Popover height has to be either the height of the NSScrollView content or the current window. Once it hits the bounds of the window it should scroll.
Using Snapkit
I have added the NSScrollView to the controller:
view.addSubview(scrollView)
scrollView.snp.makeConstraints { (make) in
make.edges.equalTo(view)
make.height.equalTo(mainView.content.snp.height)
}
This works fine until the content is greater than the window, then what happens is the NSScrollView will not scroll to the top of the content because the view has pushed itself upwards out of bounds.
I have gone down the route of removing the height constraint and in the viewDidLayout try to update the height but it doesn't work.
If more code examples are needed let me know.
Finally got to the bottom of the issue and found a sensible solution.
The app I am developing has a few popovers that are required at various stages, to ensure that they closed as required I created a service that manages every popover, here is an example:
class PopoverService: NSObject {
enum PopoverType {
case subscription, edit
}
//================================================================================
// MARK: - Properties
//================================================================================
private var dismissingPopover = false
private lazy var currentPopover: NSPopover = {
let popover = NSPopover()
popover.delegate = self
return popover
}()
private var nextPopoverType: PopoverType?
private var currentView: NSView!
public static var delegate: PopoverServiceDelegate?
//================================================================================
// MARK: - Singleton
//================================================================================
static let shared = PopoverService()
//================================================================================
// MARK: - Helpers
//================================================================================
public static func increaseHeight(_ height: CGFloat) {
shared.currentPopover.contentSize.height = height
}
public static func isDisplayingType(_ type: PopoverType) -> Bool {
switch type {
case .edit:
return shared.currentPopover.contentViewController is EditEntryController
case .language:
return shared.currentPopover.contentViewController is CodeTypeController
default:
return false
}
}
public static func displayPopover(type: PopoverType, fromView view: NSView) {
shared.nextPopoverType = type
shared.currentView = view
switch type {
case .subscription:
displaySubscriptionPopoverFrom(view)
// Create functions to display your popovers
}
}
static func dismissPopover(clearUpcoming: Bool = true) {
if clearUpcoming {
shared.nextPopoverType = nil
}
shared.currentPopover.performClose(nil)
if shared.currentPopover.contentViewController == nil {
shared.dismissingPopover = false; return
}
}
}
extension PopoverService: NSPopoverDelegate {
func popoverDidClose(_ notification: Notification) {
currentPopover.contentViewController = nil
dismissingPopover = false
guard let nextPopoverType = nextPopoverType else { return }
PopoverService.displayPopover(
type: nextPopoverType,
fromView: currentView,
entry: currentEntry
)
}
}
To update the current popover, there is a function increaseHeight which takes and CGFloat and will update the current popovers height.
In the NSViewController override the viewDidLayout():
override func viewDidLayout() {
super.viewDidLayout()
let windowFrameHeight = view.window?.frame.size.height ?? 0
let contentHeight = scrollView.content.frame.height
let adjustment = contentHeight > windowFrameHeight ? windowFrameHeight : contentHeight
PopoverService.increaseHeight(adjustment)
if contentHeight > 0 && firstLayout {
if let documentView = scrollView.documentView {
documentView.scroll(NSPoint(x: 0, y: documentView.bounds.size.height))
}
}
}
The scrollView will need to be forced to the top so there is a variable firstLayout which you can set to true in the viewDidAppear

How to change keyboard language in Search Bar? Swift

How can I change language in TextField:
class langField: UITextField {
var languageCode:String? {
didSet {
if self.isFirstResponder {
self.resignFirstResponder()
self.becomeFirstResponder()
}
}
}
override var textInputMode: UITextInputMode? {
if let language_code = self.languageCode {
for keyboard in UITextInputMode.activeInputModes {
if let language = keyboard.primaryLanguage {
let locale = Locale.init(identifier: language)
if locale.languageCode == language_code {
return keyboard
}
}
}
}
return super.textInputMode
}
}
Then:
let textFiled = langField()
textField.languageCode = "en"
And when user taps on your TextField language will become English
How to do the same for the search bar?
I do this:
extension UISearchBar {
func textField() -> UITextField? {
for view in subviews {
for subview in view.subviews {
if let textField = subview as? UITextField {
return textField
}
}
}
return nil
}
}
But when I call textField there is no .languageCode method

Display Only "Customize Toolbar..." in NSToolbar's Context Menu in Swift

I know this question has been asked many times but it seems no better solution for it.
Changing the allowsUserCustomization property doesn't help. It seems there is no API to customize the items in toolbar's context menu.
Finder app has no "Use Small Size" while Notes app has only "Customize Toolbar.."
I would like to know if there is any way to subclass or extend or do whatever to the NSToolbar to achieve the purpose?
Updated 1:
According to #Khundragpan and this post, problem 1 can be solved by:
if let contextMenu = window?.contentView?.superview?.menu {
for item in contextMenu.items {
if item.title != "Customize Toolbar…" {
contextMenu.removeItem(item)
}
}
}
But I don't think it's the best way.
Update 2:
Another way to solve problem 1 (thanks to #1024jp to point out this file):
if let contextMenu = window?.contentView?.superview?.menu {
contextMenu.items.forEach({ (item) in
if let action = item.action,
NSStringFromSelector(action) != "runToolbarCustomizationPalette:" {
contextMenu.removeItem(item)
}
})
}
Update 3:
A ton of thanks to #1024jp for helping me. I'm able to remove those things with a few tips and tricks from him. Check the answer below.
After 3 days, I finally did it. Here is the result.
Source Code in Swift 3
You can implement and make your own class, but here I just want to keep everything in a file.
This is the WindowController.swift file. You can set the custom class of your window controller and run. Again thanks to #1024jp for the tips.
//
// WindowController.swift
// The Toolbar
//
// Created by João Oliveira on 22/09/2016.
// Copyright © 2016 João Oliveira. All rights reserved.
//
import Cocoa
class WindowController: NSWindowController {
override func windowDidLoad() {
super.windowDidLoad()
guard let window = window else { return }
window.delegate = self
window.toolbar = NSToolbar(identifier: "RestrictedToolbar")
window.toolbar?.allowsUserCustomization = true
window.toolbar?.displayMode = .iconOnly
window.toolbar?.delegate = self
keepOnlyCustomizableMenu()
}
// PROBLEM 1: Solution
func keepOnlyCustomizableMenu() {
if let contextMenu = window?.contentView?.superview?.menu {
contextMenu.items.forEach({ (item) in
if let action = item.action,
NSStringFromSelector(action) != "runToolbarCustomizationPalette:" {
contextMenu.removeItem(item)
}
})
}
}
}
// MARK: Window Delegate
// A ton of thanks to genius #1024jp
extension MyWindowController: NSWindowDelegate {
// PROBLEM 2: Solution
func window(_ window: NSWindow, willPositionSheet sheet: NSWindow, using rect: NSRect) -> NSRect {
if sheet.className == "NSToolbarConfigPanel" {
removeSizeAndDisplayMode(in: sheet)
}
return rect
}
func removeSizeAndDisplayMode(in sheet: NSWindow) {
guard let views = sheet.contentView?.subviews else { return }
// Hide Small Size Option
views.lazy
.flatMap { $0 as? NSButton }
.filter { button -> Bool in
guard let buttonTypeValue = button.cell?.value(forKey: "buttonType") as? UInt,
let buttonType = NSButtonType(rawValue: buttonTypeValue)
else { return false }
return buttonType == .switch
}
.first?.isHidden = true
// Hide Display Mode Option
views.lazy
.filter { view -> Bool in
return view.subviews.count == 2
}
.first?.isHidden = true
sheet.contentView?.needsDisplay = true
}
}
// MARK: Toolbar Delegate
extension MyWindowController: NSToolbarDelegate {
func toolbarAllowedItemIdentifiers(_ toolbar: NSToolbar) -> [String] {
return [
NSToolbarFlexibleSpaceItemIdentifier,
NSToolbarSpaceItemIdentifier,
NSToolbarToggleSidebarItemIdentifier
]
}
func toolbarDefaultItemIdentifiers(_ toolbar: NSToolbar) -> [String] {
return [NSToolbarToggleSidebarItemIdentifier]
}
func toolbar(_ toolbar: NSToolbar, itemForItemIdentifier itemIdentifier: String, willBeInsertedIntoToolbar flag: Bool) -> NSToolbarItem? {
return nil
}
}

Login Item - cocoa

Is there a way to check if the login item already exists (with bundleIdentifier of the app?) I want to be able to see if there is a login item and if it is enable.
I was trying to check my checkbox in applicationDidFinishLuanching when the login item is enabled using this:
if (SMLoginItemSetEnabled(("bundleIDOfMyApp" as CFStringRef), true)) {
self.startAtLoginButton.state = 1
} else {
self.startAtLoginButton.state = 0
}
It does its thing, but it also launches my helper application.
Another thing is this:
#IBAction func startAtLoginButtonChecked(sender: NSButton) {
var enabled = false
if sender.state == 0 { enabled = false }
if sender.state == 1 { enabled = true }
if !SMLoginItemSetEnabled(("bundleIDOfMyApp" as CFStringRef), enabled) {
print("Login was not successful")
}
}
As far as I am concerned this is the way you implement checkbox to enable/disable login item.
What it does in my app is every time I check the box it launches the helper app (which launches my app again).
Although the method SMCopyAllJobDictionaries() is deprecated this is the usual way to check if the job is enabled, SMLoginItemSetEnabled is only be used to set the value
import ServiceManagement
let jobDicts = SMCopyAllJobDictionaries( kSMDomainUserLaunchd ).takeRetainedValue() as NSArray as! [[String:AnyObject]]
let label = "bundleIDOfMyApp"
let jobEnabled = jobDicts.filter { $0["Label"] as! String == label }.isEmpty == false
The double casting is needed to cast CFArray to NSArray and then to Array<String,AnyObject>
Also usually the checkbox is bound to a property via KVC. The lines above are the getter and SMLoginItemSetEnabled is the setter for example
let helperBundleIdentifier = "bundleIDOfMyApp"
#available(OSX, deprecated=10.10) // this line suppresses the 'deprecated' warning
dynamic var startAtLogin : Bool {
get {
guard let jobDicts = SMCopyAllJobDictionaries( kSMDomainUserLaunchd ).takeRetainedValue() as NSArray as? [[String:AnyObject]] else { return false }
return jobDicts.filter { $0["Label"] as! String == helperBundleIdentifier }.isEmpty == false
} set {
if !SMLoginItemSetEnabled(helperBundleIdentifier, newValue) {
print("SMLoginItemSetEnabled failed.")
}
}
}
Swift 3:
#available(OSX, deprecated: 10.10)
dynamic var startAtLogin : Bool {
get {
guard let jobDicts = SMCopyAllJobDictionaries( kSMDomainUserLaunchd ).takeRetainedValue() as? [[String:Any]] else { return false }
return jobDicts.first(where: { $0["Label"] as! String == helperBundleIdentifier }) != nil
} set {
if !SMLoginItemSetEnabled(helperBundleIdentifier as CFString, newValue) {
print("SMLoginItemSetEnabled failed.")
}
}
}
Side note: A launchd job requires the key Label so it's 100% safe to unwrap the optional in the filter function.