完善任务流程、键盘适配与页面交互
This commit is contained in:
14
Pods/IQKeyboardToolbarManager/IQKeyboardToolbarManager/Assets/PrivacyInfo.xcprivacy
generated
Normal file
14
Pods/IQKeyboardToolbarManager/IQKeyboardToolbarManager/Assets/PrivacyInfo.xcprivacy
generated
Normal file
@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>NSPrivacyAccessedAPITypes</key>
|
||||
<array/>
|
||||
<key>NSPrivacyTrackingDomains</key>
|
||||
<array/>
|
||||
<key>NSPrivacyCollectedDataTypes</key>
|
||||
<array/>
|
||||
<key>NSPrivacyTracking</key>
|
||||
<false/>
|
||||
</dict>
|
||||
</plist>
|
||||
@ -0,0 +1,90 @@
|
||||
//
|
||||
// IQKeyboardToolbarConfiguration.swift
|
||||
// https://github.com/hackiftekhar/IQKeyboardToolbarManager
|
||||
// Copyright (c) 2013-24 Iftekhar Qurashi.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
import UIKit
|
||||
import IQKeyboardToolbar
|
||||
|
||||
@available(iOSApplicationExtension, unavailable)
|
||||
@MainActor
|
||||
@objcMembers public final class IQKeyboardToolbarConfiguration: NSObject {
|
||||
|
||||
/**
|
||||
If YES, then uses textInputView's tintColor property,
|
||||
otherwise tint color is default. Default is NO.
|
||||
*/
|
||||
public var useTextInputViewTintColor: Bool = false
|
||||
|
||||
/**
|
||||
This is used for toolbar.tintColor when textInputView.keyboardAppearance is UIKeyboardAppearanceDefault.
|
||||
If useTextInputViewTintColor is YES then this property is ignored. Default is nil and uses black color.
|
||||
*/
|
||||
public var tintColor: UIColor?
|
||||
|
||||
/**
|
||||
This is used for toolbar.barTintColor. Default is nil.
|
||||
*/
|
||||
public var barTintColor: UIColor?
|
||||
|
||||
/**
|
||||
IQPreviousNextDisplayModeDefault: Show NextPrevious when there are more than 1 textInputView otherwise hide.
|
||||
IQPreviousNextDisplayModeAlwaysHide: Do not show NextPrevious buttons in any case.
|
||||
IQPreviousNextDisplayModeAlwaysShow: Always show nextPrevious buttons,
|
||||
if there are more than 1 textInputView then both buttons will be visible but will be shown as disabled.
|
||||
*/
|
||||
public var previousNextDisplayMode: IQPreviousNextDisplayMode = .default
|
||||
|
||||
/**
|
||||
/**
|
||||
IQAutoToolbarBySubviews: Creates Toolbar according to subview's hierarchy of TextInputView's in view.
|
||||
IQAutoToolbarByTag: Creates Toolbar according to tag property of TextInputView's.
|
||||
IQAutoToolbarByPosition: Creates Toolbar according to the y,x position
|
||||
of textInputView in it's superview coordinate.
|
||||
|
||||
Default is IQAutoToolbarBySubviews.
|
||||
*/
|
||||
AutoToolbar managing behavior. Default is IQAutoToolbarBySubviews.
|
||||
*/
|
||||
public var manageBehavior: IQKeyboardToolbarManageBehavior = .bySubviews
|
||||
|
||||
/**
|
||||
Buttons configuration displayed on the toolbar, the selector parameter is ignored in below configuration
|
||||
*/
|
||||
public var previousBarButtonConfiguration: IQBarButtonItemConfiguration?
|
||||
public var nextBarButtonConfiguration: IQBarButtonItemConfiguration?
|
||||
public var doneBarButtonConfiguration: IQBarButtonItemConfiguration?
|
||||
|
||||
public let placeholderConfiguration: IQKeyboardToolbarPlaceholderConfiguration = .init()
|
||||
}
|
||||
|
||||
// swiftlint:disable unused_setter_value
|
||||
@available(iOSApplicationExtension, unavailable)
|
||||
@MainActor
|
||||
@objc public extension IQKeyboardToolbarConfiguration {
|
||||
|
||||
@available(*, unavailable, renamed: "useTextInputViewTintColor")
|
||||
var useTextFieldTintColor: Bool {
|
||||
get { fatalError() }
|
||||
set {}
|
||||
}
|
||||
}
|
||||
// swiftlint:enable unused_setter_value
|
||||
@ -0,0 +1,68 @@
|
||||
//
|
||||
// IQKeyboardToolbarConstants.swift
|
||||
// https://github.com/hackiftekhar/IQKeyboardToolbarManager
|
||||
// Copyright (c) 2013-24 Iftekhar Qurashi.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
import Foundation
|
||||
|
||||
// MARK: IQKeyboardToolbarManageBehavior
|
||||
|
||||
/**
|
||||
`IQAutoToolbarBySubviews`
|
||||
Creates Toolbar according to subview's hierarchy of textInputView's in view.
|
||||
|
||||
`IQAutoToolbarByTag`
|
||||
Creates Toolbar according to tag property of textInputView's.
|
||||
|
||||
`IQAutoToolbarByPosition`
|
||||
Creates Toolbar according to the y,x position of textInputView in it's superview coordinate.
|
||||
*/
|
||||
@available(iOSApplicationExtension, unavailable)
|
||||
@objc public enum IQKeyboardToolbarManageBehavior: Int {
|
||||
case bySubviews
|
||||
case byTag
|
||||
case byPosition
|
||||
}
|
||||
|
||||
@available(*, unavailable, renamed: "IQKeyboardToolbarManageBehavior")
|
||||
@objc public enum IQAutoToolbarManageBehavior: Int {
|
||||
case bySubviews
|
||||
case byTag
|
||||
case byPosition
|
||||
}
|
||||
|
||||
/**
|
||||
`IQPreviousNextDisplayModeDefault`
|
||||
Show NextPrevious when there are more than 1 textInputView otherwise hide.
|
||||
|
||||
`IQPreviousNextDisplayModeAlwaysHide`
|
||||
Do not show NextPrevious buttons in any case.
|
||||
|
||||
`IQPreviousNextDisplayModeAlwaysShow`
|
||||
Always show nextPrevious buttons,
|
||||
if there are more than 1 textInputView then both buttons will be visible but will be shown as disabled.
|
||||
*/
|
||||
@available(iOSApplicationExtension, unavailable)
|
||||
@objc public enum IQPreviousNextDisplayMode: Int {
|
||||
case `default`
|
||||
case alwaysHide
|
||||
case alwaysShow
|
||||
}
|
||||
@ -0,0 +1,52 @@
|
||||
//
|
||||
// IQKeyboardToolbarManager+Debug
|
||||
// https://github.com/hackiftekhar/IQKeyboardToolbarManager
|
||||
// Copyright (c) 2013-24 Iftekhar Qurashi.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
import Foundation
|
||||
|
||||
// MARK: Debugging & Developer options
|
||||
@available(iOSApplicationExtension, unavailable)
|
||||
@MainActor
|
||||
internal extension IQKeyboardToolbarManager {
|
||||
|
||||
func showLog(_ logString: String, indentation: Int = 0) {
|
||||
|
||||
guard isDebuggingEnabled else {
|
||||
return
|
||||
}
|
||||
|
||||
if indentation < 0 {
|
||||
self.logIndentation = max(0, self.logIndentation + indentation)
|
||||
}
|
||||
|
||||
var preLog: String = "IQKeyboardToolbarManager"
|
||||
for _ in 0 ... self.logIndentation {
|
||||
preLog += "|\t"
|
||||
}
|
||||
|
||||
print(preLog + logString)
|
||||
|
||||
if indentation > 0 {
|
||||
self.logIndentation += indentation
|
||||
}
|
||||
}
|
||||
}
|
||||
29
Pods/IQKeyboardToolbarManager/IQKeyboardToolbarManager/Classes/IQDeepResponderContainerView.swift
generated
Normal file
29
Pods/IQKeyboardToolbarManager/IQKeyboardToolbarManager/Classes/IQDeepResponderContainerView.swift
generated
Normal file
@ -0,0 +1,29 @@
|
||||
//
|
||||
// IQDeepResponderContainerView.swift
|
||||
// https://github.com/hackiftekhar/IQKeyboardToolbarManager
|
||||
// Copyright (c) 2013-24 Iftekhar Qurashi.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
import UIKit
|
||||
|
||||
@available(iOSApplicationExtension, unavailable)
|
||||
@MainActor
|
||||
@objcMembers open class IQDeepResponderContainerView: UIView {
|
||||
}
|
||||
183
Pods/IQKeyboardToolbarManager/IQKeyboardToolbarManager/Classes/IQKeyboardToolbarManager+Deprecated.swift
generated
Normal file
183
Pods/IQKeyboardToolbarManager/IQKeyboardToolbarManager/Classes/IQKeyboardToolbarManager+Deprecated.swift
generated
Normal file
@ -0,0 +1,183 @@
|
||||
//
|
||||
// IQKeyboardToolbarManager+Deprecated.swift
|
||||
// https://github.com/hackiftekhar/IQKeyboardToolbarManager
|
||||
// Copyright (c) 2013-24 Iftekhar Qurashi.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
import UIKit
|
||||
import IQKeyboardToolbar
|
||||
|
||||
// swiftlint:disable unused_setter_value
|
||||
// swiftlint:disable identifier_name
|
||||
@available(iOSApplicationExtension, unavailable)
|
||||
@MainActor
|
||||
@objc public extension IQKeyboardToolbarManager {
|
||||
|
||||
@available(*, unavailable, renamed: "isEnabled")
|
||||
var enableAutoToolbar: Bool {
|
||||
get { false }
|
||||
set { }
|
||||
}
|
||||
|
||||
@available(*, unavailable, renamed: "playInputClicks")
|
||||
var shouldPlayInputClicks: Bool {
|
||||
get { false }
|
||||
set { }
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOSApplicationExtension, unavailable)
|
||||
@MainActor
|
||||
@objc public extension IQKeyboardToolbarManager {
|
||||
|
||||
@available(*, unavailable, renamed: "toolbarConfiguration.manageBehavior")
|
||||
var toolbarManageBehaviour: IQAutoToolbarManageBehavior {
|
||||
get { .bySubviews }
|
||||
set { }
|
||||
}
|
||||
|
||||
@available(*, unavailable, renamed: "toolbarConfiguration.useTextInputViewTintColor")
|
||||
var shouldToolbarUsesTextFieldTintColor: Bool {
|
||||
get { false }
|
||||
set { }
|
||||
}
|
||||
|
||||
@available(*, unavailable, renamed: "toolbarConfiguration.tintColor")
|
||||
var toolbarTintColor: UIColor? {
|
||||
get { nil }
|
||||
set { }
|
||||
}
|
||||
|
||||
@available(*, unavailable, renamed: "toolbarConfiguration.barTintColor")
|
||||
var toolbarBarTintColor: UIColor? {
|
||||
get { nil }
|
||||
set { }
|
||||
}
|
||||
|
||||
@available(*, unavailable, renamed: "toolbarConfiguration.previousNextDisplayMode")
|
||||
var previousNextDisplayMode: IQPreviousNextDisplayMode {
|
||||
get { .default }
|
||||
set { }
|
||||
}
|
||||
|
||||
@available(*, unavailable, renamed: "deepResponderAllowedContainerClasses")
|
||||
var toolbarPreviousNextAllowedClasses: [UIView.Type] {
|
||||
get { [] }
|
||||
set { }
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOSApplicationExtension, unavailable)
|
||||
@MainActor
|
||||
@objc public extension IQKeyboardToolbarManager {
|
||||
@available(*, unavailable, renamed: "toolbarConfiguration.previousBarButtonConfiguration.image",
|
||||
message: "To change, please assign a new toolbarConfiguration.previousBarButtonConfiguration")
|
||||
var toolbarPreviousBarButtonItemImage: UIImage? {
|
||||
get { nil }
|
||||
set { }
|
||||
}
|
||||
@available(*, unavailable, renamed: "toolbarConfiguration.previousBarButtonConfiguration.title",
|
||||
message: "To change, please assign a new toolbarConfiguration.previousBarButtonConfiguration")
|
||||
var toolbarPreviousBarButtonItemText: String? {
|
||||
get { nil }
|
||||
set { }
|
||||
}
|
||||
@available(*, unavailable, renamed: "toolbarConfiguration.previousBarButtonConfiguration.accessibilityLabel",
|
||||
message: "To change, please assign a new toolbarConfiguration.previousBarButtonConfiguration")
|
||||
var toolbarPreviousBarButtonItemAccessibilityLabel: String? {
|
||||
get { nil }
|
||||
set { }
|
||||
}
|
||||
|
||||
@available(*, unavailable, renamed: "toolbarConfiguration.nextBarButtonConfiguration.image",
|
||||
message: "To change, please assign a new toolbarConfiguration.nextBarButtonConfiguration")
|
||||
var toolbarNextBarButtonItemImage: UIImage? {
|
||||
get { nil }
|
||||
set { }
|
||||
}
|
||||
@available(*, unavailable, renamed: "toolbarConfiguration.nextBarButtonConfiguration.title",
|
||||
message: "To change, please assign a new toolbarConfiguration.nextBarButtonConfiguration")
|
||||
var toolbarNextBarButtonItemText: String? {
|
||||
get { nil }
|
||||
set { }
|
||||
}
|
||||
@available(*, unavailable, renamed: "toolbarConfiguration.nextBarButtonConfiguration.accessibilityLabel",
|
||||
message: "To change, please assign a new toolbarConfiguration.nextBarButtonConfiguration")
|
||||
var toolbarNextBarButtonItemAccessibilityLabel: String? {
|
||||
get { nil }
|
||||
set { }
|
||||
}
|
||||
|
||||
@available(*, unavailable, renamed: "toolbarConfiguration.doneBarButtonConfiguration.image",
|
||||
message: "To change, please assign a new toolbarConfiguration.doneBarButtonConfiguration")
|
||||
var toolbarDoneBarButtonItemImage: UIImage? {
|
||||
get { nil }
|
||||
set { }
|
||||
}
|
||||
@available(*, unavailable, renamed: "toolbarConfiguration.doneBarButtonConfiguration.title",
|
||||
message: "To change, please assign a new toolbarConfiguration.doneBarButtonConfiguration")
|
||||
var toolbarDoneBarButtonItemText: String? {
|
||||
get { nil }
|
||||
set { }
|
||||
}
|
||||
@available(*, unavailable, renamed: "toolbarConfiguration.doneBarButtonConfiguration.accessibilityLabel",
|
||||
message: "To change, please assign a new toolbarConfiguration.doneBarButtonConfiguration")
|
||||
var toolbarDoneBarButtonItemAccessibilityLabel: String? {
|
||||
get { nil }
|
||||
set { }
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOSApplicationExtension, unavailable)
|
||||
@MainActor
|
||||
@objc public extension IQKeyboardToolbarManager {
|
||||
|
||||
@available(*, unavailable, renamed: "toolbarConfiguration.placeholderConfiguration.accessibilityLabel")
|
||||
var toolbarTitleBarButtonItemAccessibilityLabel: String? {
|
||||
get { nil }
|
||||
set { }
|
||||
}
|
||||
|
||||
@available(*, unavailable, renamed: "toolbarConfiguration.placeholderConfiguration.showPlaceholder")
|
||||
var shouldShowToolbarPlaceholder: Bool {
|
||||
get { false }
|
||||
set { }
|
||||
}
|
||||
|
||||
@available(*, unavailable, renamed: "toolbarConfiguration.placeholderConfiguration.font")
|
||||
var placeholderFont: UIFont? {
|
||||
get { nil }
|
||||
set { }
|
||||
}
|
||||
|
||||
@available(*, unavailable, renamed: "toolbarConfiguration.placeholderConfiguration.color")
|
||||
var placeholderColor: UIColor? {
|
||||
get { nil }
|
||||
set { }
|
||||
}
|
||||
|
||||
@available(*, unavailable, renamed: "toolbarConfiguration.placeholderConfiguration.buttonColor")
|
||||
var placeholderButtonColor: UIColor? {
|
||||
get { nil }
|
||||
set { }
|
||||
}
|
||||
}
|
||||
// swiftlint:enable unused_setter_value
|
||||
// swiftlint:enable identifier_name
|
||||
148
Pods/IQKeyboardToolbarManager/IQKeyboardToolbarManager/Classes/IQKeyboardToolbarManager+Internal.swift
generated
Normal file
148
Pods/IQKeyboardToolbarManager/IQKeyboardToolbarManager/Classes/IQKeyboardToolbarManager+Internal.swift
generated
Normal file
@ -0,0 +1,148 @@
|
||||
//
|
||||
// IQKeyboardToolbarManager+Internal.swift
|
||||
// https://github.com/hackiftekhar/IQKeyboardToolbarManager
|
||||
// Copyright (c) 2013-24 Iftekhar Qurashi.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
import UIKit
|
||||
import IQTextInputViewNotification
|
||||
import IQKeyboardCore
|
||||
|
||||
@available(iOSApplicationExtension, unavailable)
|
||||
@MainActor
|
||||
internal extension IQKeyboardToolbarManager {
|
||||
|
||||
/** Get all textInputView siblings of textInputView. */
|
||||
func responderViews(of textInputView: some IQTextInputView) -> [any IQTextInputView]? {
|
||||
|
||||
var superConsideredView: UIView?
|
||||
|
||||
// If find any consider responderView in it's upper hierarchy then will get deepResponderView.
|
||||
for allowedClass in deepResponderAllowedContainerClasses {
|
||||
superConsideredView = (textInputView as UIView).iq.superviewOf(type: allowedClass)
|
||||
if superConsideredView != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
let swiftUIHostingView: UIView? = Self.getSwiftUIHostingView(textInputView: textInputView)
|
||||
|
||||
// (Enhancement ID: #22)
|
||||
// If there is a superConsideredView in view's hierarchy,
|
||||
// then fetching all it's subview that responds.
|
||||
// No sorting for superConsideredView, it's by subView position.
|
||||
if let view: UIView = swiftUIHostingView {
|
||||
return view.iq.deepResponderViews()
|
||||
} else if let view: UIView = superConsideredView {
|
||||
return view.iq.deepResponderViews()
|
||||
} else { // Otherwise fetching all the siblings
|
||||
|
||||
let textInputViews: [any IQTextInputView] = textInputView.iq.responderSiblings()
|
||||
|
||||
// Sorting textInputViews according to behavior
|
||||
switch toolbarConfiguration.manageBehavior {
|
||||
// If autoToolbar behavior is bySubviews, then returning it.
|
||||
case .bySubviews: return textInputViews
|
||||
|
||||
// If autoToolbar behavior is by tag, then sorting it according to tag property.
|
||||
case .byTag: return textInputViews.sortedByTag()
|
||||
|
||||
// If autoToolbar behavior is by tag, then sorting it according to tag property.
|
||||
case .byPosition: return textInputViews.sortedByPosition()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func privateIsEnableAutoToolbar(of textInputView: some IQTextInputView) -> Bool {
|
||||
|
||||
var isEnabled: Bool = isEnabled
|
||||
|
||||
guard var textInputViewController = (textInputView as UIView).iq.viewContainingController() else {
|
||||
return isEnabled
|
||||
}
|
||||
|
||||
if textInputView is UISearchTextField {
|
||||
if let navController: UINavigationController = textInputViewController as? UINavigationController,
|
||||
let topController: UIViewController = navController.topViewController {
|
||||
textInputViewController = topController
|
||||
}
|
||||
|
||||
// Not adding toolbar for searchTextField inside searchController.
|
||||
if textInputViewController.navigationItem.searchController?.searchBar.searchTextField == textInputView {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
if !isEnabled, enabledToolbarClasses.contains(where: { textInputViewController.isKind(of: $0) }) {
|
||||
isEnabled = true
|
||||
}
|
||||
|
||||
if isEnabled {
|
||||
|
||||
// If found any toolbar disabled classes then return.
|
||||
if disabledToolbarClasses.contains(where: { textInputViewController.isKind(of: $0) }) {
|
||||
isEnabled = false
|
||||
}
|
||||
|
||||
// Special Controllers
|
||||
if isEnabled {
|
||||
|
||||
let classNameString: String = "\(type(of: textInputViewController.self))"
|
||||
|
||||
// _UIAlertControllerTextFieldViewController
|
||||
if classNameString.contains("UIAlertController"),
|
||||
classNameString.hasSuffix("TextFieldViewController") {
|
||||
isEnabled = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return isEnabled
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOSApplicationExtension, unavailable)
|
||||
@MainActor
|
||||
private extension IQKeyboardToolbarManager {
|
||||
|
||||
private static func getSwiftUIHostingView(textInputView: some IQTextInputView) -> UIView? {
|
||||
var swiftUIHostingView: UIView?
|
||||
let swiftUIHostingViewName: String = "UIHostingView<"
|
||||
var superView: UIView? = textInputView.superview
|
||||
while let aSuperview: UIView = superView {
|
||||
|
||||
let classNameString: String = {
|
||||
var name: String = "\(type(of: aSuperview.self))"
|
||||
if name.hasPrefix("_") {
|
||||
name.removeFirst()
|
||||
}
|
||||
return name
|
||||
}()
|
||||
|
||||
if classNameString.hasPrefix(swiftUIHostingViewName) {
|
||||
swiftUIHostingView = aSuperview
|
||||
break
|
||||
}
|
||||
|
||||
superView = aSuperview.superview
|
||||
}
|
||||
return swiftUIHostingView
|
||||
}
|
||||
}
|
||||
173
Pods/IQKeyboardToolbarManager/IQKeyboardToolbarManager/Classes/IQKeyboardToolbarManager.swift
generated
Normal file
173
Pods/IQKeyboardToolbarManager/IQKeyboardToolbarManager/Classes/IQKeyboardToolbarManager.swift
generated
Normal file
@ -0,0 +1,173 @@
|
||||
//
|
||||
// IQKeyboardToolbarManager.swift
|
||||
// https://github.com/hackiftekhar/IQKeyboardToolbarManager
|
||||
// Copyright (c) 2013-24 Iftekhar Qurashi.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
import UIKit
|
||||
import IQTextInputViewNotification
|
||||
import IQKeyboardCore
|
||||
import IQKeyboardToolbar
|
||||
import Combine
|
||||
|
||||
@available(iOSApplicationExtension, unavailable)
|
||||
@MainActor
|
||||
@objcMembers public final class IQKeyboardToolbarManager: NSObject {
|
||||
|
||||
private let textInputViewObserver: IQTextInputViewNotification = .init()
|
||||
private var storage: Set<AnyCancellable> = []
|
||||
|
||||
internal var textInputView: (some IQTextInputView)? {
|
||||
textInputViewObserver.textInputView
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the default singleton instance.
|
||||
*/
|
||||
@MainActor
|
||||
@objc public static let shared: IQKeyboardToolbarManager = .init()
|
||||
|
||||
/**
|
||||
Automatic add the toolbar functionality. Default is false.
|
||||
*/
|
||||
public var isEnabled: Bool = false {
|
||||
didSet {
|
||||
reloadInputViews()
|
||||
showLog("isEnabled: \(isEnabled ? "Yes" : "NO")")
|
||||
}
|
||||
}
|
||||
|
||||
public var isDebuggingEnabled: Bool = false
|
||||
|
||||
/**
|
||||
Configurations related to the toolbar display over the keyboard.
|
||||
*/
|
||||
public let toolbarConfiguration: IQKeyboardToolbarConfiguration = .init()
|
||||
|
||||
// MARK: UISound handling
|
||||
|
||||
/**
|
||||
If YES, then it plays inputClick sound on next/previous/done click.
|
||||
*/
|
||||
public var playInputClicks: Bool = true
|
||||
|
||||
/**
|
||||
Disable automatic toolbar creation within the scope of disabled toolbar viewControllers classes.
|
||||
Within this scope, 'isEnabled' property is ignored. Class should be kind of UIViewController.
|
||||
*/
|
||||
public var disabledToolbarClasses: [UIViewController.Type] = [
|
||||
UIAlertController.self,
|
||||
UIInputViewController.self
|
||||
]
|
||||
|
||||
/**
|
||||
Enable automatic toolbar creation within the scope of enabled toolbar viewControllers classes.
|
||||
Within this scope, 'isEnabled' property is ignored. Class should be kind of UIViewController.
|
||||
If same Class is added in disabledToolbarClasses list, then enabledToolbarClasses will be ignore.
|
||||
*/
|
||||
public var enabledToolbarClasses: [UIViewController.Type] = []
|
||||
|
||||
/**
|
||||
Allowed subclasses of UIView to add all inner textInputView,
|
||||
this will allow to navigate between textInputView contains in different superview.
|
||||
Class should be kind of UIView.
|
||||
*/
|
||||
public var deepResponderAllowedContainerClasses: [UIView.Type] = [
|
||||
UITableView.self,
|
||||
UICollectionView.self,
|
||||
IQDeepResponderContainerView.self
|
||||
]
|
||||
|
||||
internal var logIndentation = 0
|
||||
|
||||
internal override init() {
|
||||
super.init()
|
||||
|
||||
addTextInputViewObserver()
|
||||
addBecomeActiveObserver()
|
||||
|
||||
// (Bug ID: #550)
|
||||
// Loading IQKeyboardToolbar, IQTitleBarButtonItem, IQBarButtonItem to fix first time keyboard appearance delay
|
||||
// If you experience exception breakpoint issue at below line then try these solutions
|
||||
// https://stackoverflow.com/questions/27375640/all-exception-break-point-is-stopping-for-no-reason-on-simulator
|
||||
DispatchQueue.main.async {
|
||||
let textInputView: UITextField = UITextField()
|
||||
textInputView.iq.addDone(target: nil, action: #selector(self.doneAction(_:)))
|
||||
textInputView.iq.addPreviousNextDone(target: nil,
|
||||
previousAction: #selector(self.previousAction(_:)),
|
||||
nextAction: #selector(self.nextAction(_:)),
|
||||
doneAction: #selector(self.doneAction(_:)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOSApplicationExtension, unavailable)
|
||||
@MainActor
|
||||
private extension IQKeyboardToolbarManager {
|
||||
|
||||
private func removeTextInputViewObserver() {
|
||||
textInputViewObserver.unsubscribe(identifier: "IQKeyboardToolbarManager")
|
||||
}
|
||||
|
||||
private func addTextInputViewObserver() {
|
||||
textInputViewObserver.subscribe(identifier: "IQKeyboardToolbarManager",
|
||||
changeHandler: { [weak self] event, textInputView in
|
||||
guard let self = self else { return }
|
||||
guard (textInputView as UIView).iq.isAlertViewTextField() == false else {
|
||||
return
|
||||
}
|
||||
|
||||
switch event {
|
||||
case .beginEditing:
|
||||
reloadInputViews()
|
||||
case .endEditing:
|
||||
removeToolbarIfRequired(of: textInputView)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOSApplicationExtension, unavailable)
|
||||
@MainActor
|
||||
private extension IQKeyboardToolbarManager {
|
||||
|
||||
private func removeBecomeActiveObserver() {
|
||||
storage.forEach { $0.cancel() }
|
||||
storage.removeAll()
|
||||
}
|
||||
|
||||
private func addBecomeActiveObserver() {
|
||||
let beginEditingNotificationNames: [Notification.Name] = [
|
||||
UIApplication.didBecomeActiveNotification
|
||||
]
|
||||
|
||||
for notificationName in beginEditingNotificationNames {
|
||||
NotificationCenter.default.publisher(for: notificationName)
|
||||
.sink(receiveValue: { [weak self] info in
|
||||
guard let self = self else { return }
|
||||
|
||||
// In SwiftUI View's when app comes from background to foreground
|
||||
// The inputAccessoryView was getting removed in iOS 26. So forcing to reload.
|
||||
self.reloadInputViews()
|
||||
})
|
||||
.store(in: &storage)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,210 @@
|
||||
//
|
||||
// IQKeyboardToolbarManager+Action.swift
|
||||
// https://github.com/hackiftekhar/IQKeyboardToolbarManager
|
||||
// Copyright (c) 2013-24 Iftekhar Qurashi.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
import UIKit
|
||||
import IQKeyboardCore
|
||||
import IQKeyboardToolbar
|
||||
|
||||
// MARK: Previous next button actions
|
||||
@available(iOSApplicationExtension, unavailable)
|
||||
@MainActor
|
||||
@objc public extension IQKeyboardToolbarManager {
|
||||
|
||||
/**
|
||||
Returns YES if can navigate to previous responder textInputView, otherwise NO.
|
||||
*/
|
||||
var canGoPrevious: Bool {
|
||||
// If it is not first textInputView. then it's previous object canBecomeFirstResponder.
|
||||
guard let textInputView: any IQTextInputView = self.textInputView,
|
||||
let textInputViews: [any IQTextInputView] = responderViews(of: textInputView),
|
||||
let index: Int = textInputViews.firstIndex(where: { $0 == textInputView }),
|
||||
index > 0 else {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
Returns YES if can navigate to next responder textInputViews, otherwise NO.
|
||||
*/
|
||||
var canGoNext: Bool {
|
||||
// If it is not first textInputView. then it's previous object canBecomeFirstResponder.
|
||||
guard let textInputView: any IQTextInputView = self.textInputView,
|
||||
let textInputViews: [any IQTextInputView] = responderViews(of: textInputView),
|
||||
let index: Int = textInputViews.firstIndex(where: { $0 == textInputView }),
|
||||
index < textInputViews.count-1 else {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
Navigate to previous responder textInputViews
|
||||
*/
|
||||
@discardableResult
|
||||
func goPrevious() -> Bool {
|
||||
|
||||
// If it is not first textInputView. then it's previous object becomeFirstResponder.
|
||||
guard let textInputView: any IQTextInputView = self.textInputView,
|
||||
let textInputViews: [any IQTextInputView] = responderViews(of: textInputView),
|
||||
let index: Int = textInputViews.firstIndex(where: { $0 == textInputView }),
|
||||
index > 0 else {
|
||||
return false
|
||||
}
|
||||
|
||||
let nextTextInputView: any IQTextInputView = textInputViews[index-1]
|
||||
|
||||
let isAcceptAsFirstResponder: Bool = nextTextInputView.becomeFirstResponder()
|
||||
|
||||
// If it refuses then becoming previous textInputView as first responder again. (Bug ID: #96)
|
||||
if !isAcceptAsFirstResponder {
|
||||
showLog("Refuses to become first responder: \(nextTextInputView)")
|
||||
}
|
||||
|
||||
return isAcceptAsFirstResponder
|
||||
}
|
||||
|
||||
/**
|
||||
Navigate to next responder textInputView.
|
||||
*/
|
||||
@discardableResult
|
||||
func goNext() -> Bool {
|
||||
|
||||
// If it is not first textInputView. then it's previous object becomeFirstResponder.
|
||||
guard let textInputView: any IQTextInputView = self.textInputView,
|
||||
let textInputViews: [any IQTextInputView] = responderViews(of: textInputView),
|
||||
let index: Int = textInputViews.firstIndex(where: { $0 == textInputView }),
|
||||
index < textInputViews.count-1 else {
|
||||
return false
|
||||
}
|
||||
|
||||
let nextTextInputView: any IQTextInputView = textInputViews[index+1]
|
||||
|
||||
let isAcceptAsFirstResponder: Bool = nextTextInputView.becomeFirstResponder()
|
||||
|
||||
// If it refuses then becoming previous textInputView as first responder again. (Bug ID: #96)
|
||||
if !isAcceptAsFirstResponder {
|
||||
showLog("Refuses to become first responder: \(nextTextInputView)")
|
||||
}
|
||||
|
||||
return isAcceptAsFirstResponder
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOSApplicationExtension, unavailable)
|
||||
@MainActor
|
||||
internal extension IQKeyboardToolbarManager {
|
||||
|
||||
/** previousAction. */
|
||||
func previousAction(_ barButton: IQBarButtonItem) {
|
||||
|
||||
// If user wants to play input Click sound.
|
||||
if playInputClicks {
|
||||
// Play Input Click Sound.
|
||||
UIDevice.current.playInputClick()
|
||||
}
|
||||
|
||||
guard canGoPrevious,
|
||||
let textInputView: any IQTextInputView = self.textInputView else {
|
||||
return
|
||||
}
|
||||
|
||||
let isAcceptedAsFirstResponder: Bool = goPrevious()
|
||||
|
||||
if isAcceptedAsFirstResponder {
|
||||
Self.sendInvokeAction(of: barButton, sender: textInputView)
|
||||
}
|
||||
}
|
||||
|
||||
/** nextAction. */
|
||||
func nextAction(_ barButton: IQBarButtonItem) {
|
||||
|
||||
// If user wants to play input Click sound.
|
||||
if playInputClicks {
|
||||
// Play Input Click Sound.
|
||||
UIDevice.current.playInputClick()
|
||||
}
|
||||
|
||||
guard canGoNext,
|
||||
let textInputView: any IQTextInputView = self.textInputView else {
|
||||
return
|
||||
}
|
||||
|
||||
let isAcceptedAsFirstResponder: Bool = goNext()
|
||||
|
||||
if isAcceptedAsFirstResponder {
|
||||
Self.sendInvokeAction(of: barButton, sender: textInputView)
|
||||
}
|
||||
}
|
||||
|
||||
/** doneAction. Resigning current textInputView. */
|
||||
func doneAction(_ barButton: IQBarButtonItem) {
|
||||
|
||||
// If user wants to play input Click sound.
|
||||
if playInputClicks {
|
||||
// Play Input Click Sound.
|
||||
UIDevice.current.playInputClick()
|
||||
}
|
||||
|
||||
guard let textInputView: any IQTextInputView = self.textInputView else {
|
||||
return
|
||||
}
|
||||
|
||||
// Resign textInputView.
|
||||
let isResignedFirstResponder: Bool = textInputView.resignFirstResponder()
|
||||
|
||||
if isResignedFirstResponder {
|
||||
Self.sendInvokeAction(of: barButton, sender: textInputView)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOSApplicationExtension, unavailable)
|
||||
@MainActor
|
||||
private extension IQKeyboardToolbarManager {
|
||||
private static func sendInvokeAction(of barButton: IQBarButtonItem, sender: some IQTextInputView) {
|
||||
// Handling search bar special case
|
||||
if let searchBar: UISearchBar = sender.iq.textFieldSearchBar() {
|
||||
switch barButton {
|
||||
case sender.internalToolbar.nextBarButton:
|
||||
searchBar.internalToolbar.nextBarButton.invocation?.invoke(from: searchBar)
|
||||
case sender.internalToolbar.previousBarButton:
|
||||
searchBar.internalToolbar.previousBarButton.invocation?.invoke(from: searchBar)
|
||||
case sender.internalToolbar.doneBarButton:
|
||||
searchBar.internalToolbar.doneBarButton.invocation?.invoke(from: searchBar)
|
||||
default:
|
||||
break
|
||||
}
|
||||
} else {
|
||||
barButton.invocation?.invoke(from: sender)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOSApplicationExtension, unavailable)
|
||||
@MainActor
|
||||
fileprivate extension IQTextInputView {
|
||||
var internalToolbar: IQKeyboardToolbar {
|
||||
return iq.toolbar
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,287 @@
|
||||
//
|
||||
// IQKeyboardToolbarManager+Toolbar.swift
|
||||
// https://github.com/hackiftekhar/IQKeyboardToolbarManager
|
||||
// Copyright (c) 2013-24 Iftekhar Qurashi.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
import UIKit
|
||||
import IQKeyboardCore
|
||||
import IQKeyboardToolbar
|
||||
|
||||
@available(iOSApplicationExtension, unavailable)
|
||||
@MainActor
|
||||
@objc public extension IQKeyboardToolbarManager {
|
||||
/** reloadInputViews to reload toolbar buttons enable/disable state on the fly Enhancement ID #434. */
|
||||
func reloadInputViews() {
|
||||
|
||||
guard let textInputView = textInputView else { return }
|
||||
// If enabled then adding toolbar.
|
||||
if privateIsEnableAutoToolbar(of: textInputView) {
|
||||
self.addToolbarIfRequired(of: textInputView)
|
||||
} else {
|
||||
self.removeToolbarIfRequired(of: textInputView)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOSApplicationExtension, unavailable)
|
||||
@MainActor
|
||||
internal extension IQKeyboardToolbarManager {
|
||||
|
||||
/**
|
||||
Default tag for toolbar with Done button -1001
|
||||
*/
|
||||
private static let toolbarTag = -1001
|
||||
|
||||
// swiftlint:disable function_body_length
|
||||
// swiftlint:disable cyclomatic_complexity
|
||||
/**
|
||||
Add toolbar if it is required to add on textInputViews and it's siblings.
|
||||
*/
|
||||
func addToolbarIfRequired(of textInputView: some IQTextInputView) {
|
||||
|
||||
// Either there is no inputAccessoryView or
|
||||
// if accessoryView is not appropriate for current situation
|
||||
// (There is Previous/Next/Done toolbar)
|
||||
guard let siblings: [any IQTextInputView] = responderViews(of: textInputView), !siblings.isEmpty,
|
||||
!Self.hasUserDefinedInputAccessoryView(textInputView: textInputView) else {
|
||||
return
|
||||
}
|
||||
|
||||
showLog(">>>>> \(#function) started >>>>>", indentation: 1)
|
||||
defer {
|
||||
showLog("<<<<< \(#function) ended <<<<<", indentation: -1)
|
||||
}
|
||||
|
||||
showLog("Found \(siblings.count) responder sibling(s)")
|
||||
let rightConfiguration: IQBarButtonItemConfiguration = getRightConfiguration()
|
||||
|
||||
let isTableCollectionView: Bool
|
||||
if (textInputView as UIView).iq.superviewOf(type: UITableView.self) != nil ||
|
||||
(textInputView as UIView).iq.superviewOf(type: UICollectionView.self) != nil {
|
||||
isTableCollectionView = true
|
||||
} else {
|
||||
isTableCollectionView = false
|
||||
}
|
||||
|
||||
let previousNextDisplayMode: IQPreviousNextDisplayMode = toolbarConfiguration.previousNextDisplayMode
|
||||
|
||||
let havePreviousNext: Bool
|
||||
switch previousNextDisplayMode {
|
||||
case .default:
|
||||
// If the textInputView is part of UITableView/UICollectionView then we should be exposing previous/next too
|
||||
// Because at this time we don't know previous or next cell if it contains another textInputView to move.
|
||||
if isTableCollectionView {
|
||||
havePreviousNext = true
|
||||
} else if siblings.count <= 1 {
|
||||
// If only one object is found, then adding only Done button.
|
||||
havePreviousNext = false
|
||||
} else {
|
||||
havePreviousNext = true
|
||||
}
|
||||
case .alwaysShow:
|
||||
havePreviousNext = true
|
||||
case .alwaysHide:
|
||||
havePreviousNext = false
|
||||
}
|
||||
|
||||
let placeholderConfig: IQKeyboardToolbarPlaceholderConfiguration = toolbarConfiguration.placeholderConfiguration
|
||||
let titleText: String? = placeholderConfig.showPlaceholder ? textInputView.iq.drawingPlaceholder : nil
|
||||
if havePreviousNext {
|
||||
let prevConfiguration: IQBarButtonItemConfiguration = getPreviousConfiguration()
|
||||
let nextConfiguration: IQBarButtonItemConfiguration = getNextConfiguration()
|
||||
|
||||
textInputView.iq.addToolbar(target: self,
|
||||
previousConfiguration: prevConfiguration,
|
||||
nextConfiguration: nextConfiguration,
|
||||
rightConfiguration: rightConfiguration, title: titleText,
|
||||
titleAccessibilityLabel: placeholderConfig.accessibilityLabel)
|
||||
if isTableCollectionView {
|
||||
// (Bug ID: #56)
|
||||
// In case of UITableView, the next/previous buttons should always be enabled.
|
||||
textInputView.iq.toolbar.previousBarButton.isEnabled = true
|
||||
textInputView.iq.toolbar.nextBarButton.isEnabled = true
|
||||
} else {
|
||||
// If first textInputView, then previous should not be enabled.
|
||||
if let first = siblings.first {
|
||||
textInputView.iq.toolbar.previousBarButton.isEnabled = first != textInputView
|
||||
} else {
|
||||
textInputView.iq.toolbar.previousBarButton.isEnabled = false
|
||||
}
|
||||
// If last textInputView, then next should not be enabled.
|
||||
if let last = siblings.last {
|
||||
textInputView.iq.toolbar.nextBarButton.isEnabled = last != textInputView
|
||||
} else {
|
||||
textInputView.iq.toolbar.nextBarButton.isEnabled = false
|
||||
}
|
||||
}
|
||||
} else {
|
||||
textInputView.iq.addToolbar(target: self, rightConfiguration: rightConfiguration,
|
||||
title: titleText,
|
||||
titleAccessibilityLabel: placeholderConfig.accessibilityLabel)
|
||||
}
|
||||
// (Bug ID: #78)
|
||||
textInputView.inputAccessoryView?.tag = IQKeyboardToolbarManager.toolbarTag
|
||||
|
||||
Self.applyToolbarConfiguration(textInputView: textInputView, toolbarConfiguration: toolbarConfiguration)
|
||||
}
|
||||
// swiftlint:enable function_body_length
|
||||
// swiftlint:enable cyclomatic_complexity
|
||||
|
||||
/** Remove any toolbar if it is IQKeyboardToolbar. */
|
||||
func removeToolbarIfRequired(of textInputView: some IQTextInputView) { // (Bug ID: #18)
|
||||
|
||||
guard let toolbar: IQKeyboardToolbar = textInputView.inputAccessoryView as? IQKeyboardToolbar,
|
||||
toolbar.tag == IQKeyboardToolbarManager.toolbarTag else {
|
||||
return
|
||||
}
|
||||
|
||||
showLog(">>>>> \(#function) started >>>>>", indentation: 1)
|
||||
|
||||
defer {
|
||||
showLog("<<<<< \(#function) ended <<<<<", indentation: -1)
|
||||
}
|
||||
|
||||
textInputView.inputAccessoryView = nil
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOSApplicationExtension, unavailable)
|
||||
@MainActor
|
||||
private extension IQKeyboardToolbarManager {
|
||||
|
||||
static func hasUserDefinedInputAccessoryView(textInputView: some IQTextInputView) -> Bool {
|
||||
guard let inputAccessoryView: UIView = textInputView.inputAccessoryView,
|
||||
inputAccessoryView.tag != IQKeyboardToolbarManager.toolbarTag else { return false }
|
||||
|
||||
let swiftUIAccessoryNamePrefixes: [String] = [
|
||||
"InputAccessoryHost<InputAccessoryBar>", // iOS 17 and below
|
||||
"RootUIView", // iOS 18
|
||||
"_UIInputViewContent", // iOS 18 system views
|
||||
"_UIKeyboardInputAccessory" // Additional iOS 18 system view
|
||||
]
|
||||
let classNameString: String = "\(type(of: inputAccessoryView.classForCoder))"
|
||||
|
||||
// If it's SwiftUI accessory view but doesn't have a height (fake accessory view), then we should
|
||||
// add our own accessoryView otherwise, keep the SwiftUI accessoryView since user has added it from code
|
||||
let isSwiftUIAccessoryView = swiftUIAccessoryNamePrefixes.contains(where: { classNameString.hasPrefix($0) })
|
||||
|
||||
// A height of 0 or very small height typically indicates a system placeholder
|
||||
guard isSwiftUIAccessoryView,
|
||||
inputAccessoryView.subviews.isEmpty else {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func getRightConfiguration() -> IQBarButtonItemConfiguration {
|
||||
let rightConfiguration: IQBarButtonItemConfiguration
|
||||
if let configuration: IQBarButtonItemConfiguration = toolbarConfiguration.doneBarButtonConfiguration {
|
||||
rightConfiguration = configuration
|
||||
rightConfiguration.action = #selector(self.doneAction(_:))
|
||||
} else {
|
||||
#if compiler(>=6.2) // Xcode 26
|
||||
let requiresCompatibility: Bool = Bundle.main.object(forInfoDictionaryKey: "UIDesignRequiresCompatibility") as? Bool ?? false
|
||||
if #available(iOS 26.0, *), !requiresCompatibility {
|
||||
rightConfiguration = IQBarButtonItemConfiguration(image: UIImage(systemName: "checkmark")!, action: #selector(self.doneAction(_:)))
|
||||
} else {
|
||||
rightConfiguration = IQBarButtonItemConfiguration(systemItem: .done, action: #selector(self.doneAction(_:)))
|
||||
}
|
||||
#else
|
||||
rightConfiguration = IQBarButtonItemConfiguration(systemItem: .done, action: #selector(self.doneAction(_:)))
|
||||
#endif
|
||||
rightConfiguration.accessibilityLabel = "Done"
|
||||
}
|
||||
return rightConfiguration
|
||||
}
|
||||
|
||||
func getPreviousConfiguration() -> IQBarButtonItemConfiguration {
|
||||
let prevConfiguration: IQBarButtonItemConfiguration
|
||||
if let configuration: IQBarButtonItemConfiguration = toolbarConfiguration.previousBarButtonConfiguration {
|
||||
configuration.action = #selector(self.previousAction(_:))
|
||||
prevConfiguration = configuration
|
||||
} else {
|
||||
let chevronUp: UIImage = UIImage(systemName: "chevron.up") ?? UIImage()
|
||||
prevConfiguration = IQBarButtonItemConfiguration(image: chevronUp,
|
||||
action: #selector(self.previousAction(_:)))
|
||||
prevConfiguration.accessibilityLabel = "Previous"
|
||||
}
|
||||
return prevConfiguration
|
||||
}
|
||||
|
||||
func getNextConfiguration() -> IQBarButtonItemConfiguration {
|
||||
let nextConfiguration: IQBarButtonItemConfiguration
|
||||
if let configuration: IQBarButtonItemConfiguration = toolbarConfiguration.nextBarButtonConfiguration {
|
||||
configuration.action = #selector(self.nextAction(_:))
|
||||
nextConfiguration = configuration
|
||||
} else {
|
||||
let chevronDown: UIImage = UIImage(systemName: "chevron.down") ?? UIImage()
|
||||
nextConfiguration = IQBarButtonItemConfiguration(image: chevronDown,
|
||||
action: #selector(self.nextAction(_:)))
|
||||
nextConfiguration.accessibilityLabel = "Next"
|
||||
}
|
||||
return nextConfiguration
|
||||
}
|
||||
|
||||
static func applyToolbarConfiguration(textInputView: some IQTextInputView,
|
||||
toolbarConfiguration: IQKeyboardToolbarConfiguration) {
|
||||
|
||||
let toolbar: IQKeyboardToolbar = textInputView.iq.toolbar
|
||||
|
||||
// Setting toolbar tintColor // (Enhancement ID: #30)
|
||||
if toolbarConfiguration.useTextInputViewTintColor {
|
||||
toolbar.tintColor = textInputView.tintColor
|
||||
} else {
|
||||
toolbar.tintColor = toolbarConfiguration.tintColor
|
||||
}
|
||||
|
||||
// Bar style according to keyboard appearance
|
||||
switch textInputView.keyboardAppearance {
|
||||
case .dark:
|
||||
toolbar.barStyle = .black
|
||||
toolbar.barTintColor = nil
|
||||
default:
|
||||
toolbar.barStyle = .default
|
||||
toolbar.barTintColor = toolbarConfiguration.barTintColor
|
||||
}
|
||||
|
||||
// Setting toolbar title font. // (Enhancement ID: #30)
|
||||
guard toolbarConfiguration.placeholderConfiguration.showPlaceholder,
|
||||
!textInputView.iq.hidePlaceholder else {
|
||||
toolbar.titleBarButton.title = nil
|
||||
return
|
||||
}
|
||||
|
||||
// Updating placeholder font to toolbar. //(Bug ID: #148, #272)
|
||||
if toolbar.titleBarButton.title == nil ||
|
||||
toolbar.titleBarButton.title != textInputView.iq.drawingPlaceholder {
|
||||
toolbar.titleBarButton.title = textInputView.iq.drawingPlaceholder
|
||||
}
|
||||
|
||||
// Setting toolbar title font. // (Enhancement ID: #30)
|
||||
toolbar.titleBarButton.titleFont = toolbarConfiguration.placeholderConfiguration.font
|
||||
|
||||
// Setting toolbar title color. // (Enhancement ID: #880)
|
||||
toolbar.titleBarButton.titleColor = toolbarConfiguration.placeholderConfiguration.color
|
||||
|
||||
// Setting toolbar button title color. // (Enhancement ID: #880)
|
||||
toolbar.titleBarButton.selectableTitleColor = toolbarConfiguration.placeholderConfiguration.buttonColor
|
||||
}
|
||||
}
|
||||
58
Pods/IQKeyboardToolbarManager/IQKeyboardToolbarManager/Classes/UIKitExtensions/Array+Sort.swift
generated
Normal file
58
Pods/IQKeyboardToolbarManager/IQKeyboardToolbarManager/Classes/UIKitExtensions/Array+Sort.swift
generated
Normal file
@ -0,0 +1,58 @@
|
||||
//
|
||||
// Array+Sort.swift
|
||||
// https://github.com/hackiftekhar/IQKeyboardToolbarManager
|
||||
// Copyright (c) 2013-24 Iftekhar Qurashi.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
import UIKit
|
||||
import IQKeyboardCore
|
||||
|
||||
/**
|
||||
UIView.subviews sorting category.
|
||||
*/
|
||||
@available(iOSApplicationExtension, unavailable)
|
||||
@MainActor
|
||||
internal extension Array where Element: IQTextInputView {
|
||||
|
||||
/**
|
||||
Returns the array by sorting the UIView's by their tag property.
|
||||
*/
|
||||
func sortedByTag() -> [Element] {
|
||||
|
||||
return sorted(by: { (obj1: Element, obj2: Element) -> Bool in
|
||||
|
||||
return (obj1.tag < obj2.tag)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the array by sorting the UIView's by their tag property.
|
||||
*/
|
||||
func sortedByPosition() -> [Element] {
|
||||
|
||||
return sorted(by: { (obj1: Element, obj2: Element) -> Bool in
|
||||
if obj1.frame.minY != obj2.frame.minY {
|
||||
return obj1.frame.minY < obj2.frame.minY
|
||||
} else {
|
||||
return obj1.frame.minX < obj2.frame.minX
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
179
Pods/IQKeyboardToolbarManager/IQKeyboardToolbarManager/Classes/UIKitExtensions/UIView+Responders.swift
generated
Normal file
179
Pods/IQKeyboardToolbarManager/IQKeyboardToolbarManager/Classes/UIKitExtensions/UIView+Responders.swift
generated
Normal file
@ -0,0 +1,179 @@
|
||||
//
|
||||
// UIView+Responders.swift
|
||||
// https://github.com/hackiftekhar/IQKeyboardToolbarManager
|
||||
// Copyright (c) 2013-24 Iftekhar Qurashi.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
import UIKit
|
||||
import IQKeyboardCore
|
||||
|
||||
@available(iOSApplicationExtension, unavailable)
|
||||
@MainActor
|
||||
private struct AssociatedKeys {
|
||||
static var ignoreSwitchingByNextPrevious: Int = 0
|
||||
}
|
||||
|
||||
/**
|
||||
UIView category for managing textInputView
|
||||
*/
|
||||
@available(iOSApplicationExtension, unavailable)
|
||||
@MainActor
|
||||
public extension IQKeyboardExtension where Base: IQTextInputView {
|
||||
|
||||
/**
|
||||
If ignoreSwitchingByNextPrevious is true then library will ignore this textInputView
|
||||
while moving to other textInputView using keyboard toolbar next previous buttons.
|
||||
Default is false
|
||||
*/
|
||||
var ignoreSwitchingByNextPrevious: Bool {
|
||||
get {
|
||||
if let base = base {
|
||||
return objc_getAssociatedObject(base, &AssociatedKeys.ignoreSwitchingByNextPrevious) as? Bool ?? false
|
||||
}
|
||||
return false
|
||||
}
|
||||
set(newValue) {
|
||||
if let base = base {
|
||||
objc_setAssociatedObject(base, &AssociatedKeys.ignoreSwitchingByNextPrevious,
|
||||
newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// swiftlint:disable unused_setter_value
|
||||
@available(iOSApplicationExtension, unavailable)
|
||||
@MainActor
|
||||
@objc public extension UIView {
|
||||
@available(*, unavailable, renamed: "iq.ignoreSwitchingByNextPrevious")
|
||||
var ignoreSwitchingByNextPrevious: Bool {
|
||||
get { false }
|
||||
set { }
|
||||
}
|
||||
}
|
||||
// swiftlint:enable unused_setter_value
|
||||
|
||||
@available(iOSApplicationExtension, unavailable)
|
||||
@MainActor
|
||||
internal extension IQKeyboardExtension where Base: IQTextInputView {
|
||||
|
||||
/**
|
||||
Returns all siblings of the receiver which canBecomeFirstResponder.
|
||||
*/
|
||||
func responderSiblings() -> [any IQTextInputView] {
|
||||
|
||||
// Getting all siblings
|
||||
guard let siblings: [UIView] = base?.superview?.subviews else { return [] }
|
||||
|
||||
// Array of textInputView.
|
||||
var textInputViews: [any IQTextInputView] = []
|
||||
for view in siblings {
|
||||
if let view = view as? any IQTextInputView,
|
||||
view == base || !view.internalIgnoreSwitchingByNextPrevious,
|
||||
view.internalCanBecomeFirstResponder() {
|
||||
textInputViews.append(view)
|
||||
}
|
||||
}
|
||||
|
||||
return textInputViews
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
UIView category for managing textInputView
|
||||
*/
|
||||
@available(iOSApplicationExtension, unavailable)
|
||||
@MainActor
|
||||
internal extension IQKeyboardExtension where Base: UIView {
|
||||
|
||||
/**
|
||||
Returns all deep subViews of the receiver which canBecomeFirstResponder.
|
||||
*/
|
||||
func deepResponderViews() -> [any IQTextInputView] {
|
||||
|
||||
guard let subviews: [UIView] = base?.subviews, !subviews.isEmpty else { return [] }
|
||||
|
||||
// Array of textInputViews.
|
||||
var textInputViews: [any IQTextInputView] = []
|
||||
|
||||
for view in subviews {
|
||||
|
||||
if let view = view as? any IQTextInputView,
|
||||
view == base || !view.internalIgnoreSwitchingByNextPrevious,
|
||||
view.internalCanBecomeFirstResponder() {
|
||||
textInputViews.append(view)
|
||||
}
|
||||
// Sometimes there are hidden or disabled views and textInputView inside them still recorded,
|
||||
// so we added some more validations here (Bug ID: #458)
|
||||
// Uncommented else (Bug ID: #625)
|
||||
else if view.subviews.count != 0,
|
||||
base?.isUserInteractionEnabled == true,
|
||||
base?.isHidden == false, base?.alpha != 0.0 {
|
||||
for deepView in view.iq.deepResponderViews() {
|
||||
textInputViews.append(deepView)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// subviews are returning in opposite order. Sorting according the frames 'y'.
|
||||
return textInputViews.sorted(by: { (view1: any IQTextInputView, view2: any IQTextInputView) -> Bool in
|
||||
|
||||
let frame1: CGRect = view1.convert(view1.bounds, to: base)
|
||||
let frame2: CGRect = view2.convert(view2.bounds, to: base)
|
||||
|
||||
if frame1.minY != frame2.minY {
|
||||
return frame1.minY < frame2.minY
|
||||
} else {
|
||||
return frame1.minX < frame2.minX
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOSApplicationExtension, unavailable)
|
||||
@MainActor
|
||||
private extension IQKeyboardExtension where Base: IQTextInputView {
|
||||
|
||||
func canBecomeFirstResponder() -> Bool {
|
||||
|
||||
var canBecomeFirstResponder: Bool = base?.iqIsEnabled == true
|
||||
|
||||
if canBecomeFirstResponder {
|
||||
canBecomeFirstResponder = base?.isUserInteractionEnabled == true &&
|
||||
base?.isHidden == false &&
|
||||
base?.alpha != 0.0 &&
|
||||
!isAlertViewTextField() &&
|
||||
textFieldSearchBar() == nil
|
||||
}
|
||||
|
||||
return canBecomeFirstResponder
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOSApplicationExtension, unavailable)
|
||||
@MainActor
|
||||
fileprivate extension IQTextInputView {
|
||||
var internalIgnoreSwitchingByNextPrevious: Bool {
|
||||
return iq.ignoreSwitchingByNextPrevious
|
||||
}
|
||||
func internalCanBecomeFirstResponder() -> Bool {
|
||||
return iq.canBecomeFirstResponder()
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,44 @@
|
||||
//
|
||||
// UIView+RespondersObjc.swift
|
||||
// https://github.com/hackiftekhar/IQKeyboardToolbar
|
||||
// Copyright (c) 2013-24 Iftekhar Qurashi.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
import UIKit
|
||||
|
||||
// MARK: For ObjectiveC Compatibility
|
||||
|
||||
// swiftlint:disable identifier_name
|
||||
@objc public extension UITextField {
|
||||
|
||||
var iq_ignoreSwitchingByNextPrevious: Bool {
|
||||
get { iq.ignoreSwitchingByNextPrevious }
|
||||
set { iq.ignoreSwitchingByNextPrevious = newValue }
|
||||
}
|
||||
}
|
||||
|
||||
@objc public extension UITextView {
|
||||
|
||||
var iq_ignoreSwitchingByNextPrevious: Bool {
|
||||
get { iq.ignoreSwitchingByNextPrevious }
|
||||
set { iq.ignoreSwitchingByNextPrevious = newValue }
|
||||
}
|
||||
}
|
||||
// swiftlint:enable identifier_name
|
||||
21
Pods/IQKeyboardToolbarManager/LICENSE
generated
Normal file
21
Pods/IQKeyboardToolbarManager/LICENSE
generated
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2024 Mohd Iftekhar Qurashi
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
134
Pods/IQKeyboardToolbarManager/README.md
generated
Normal file
134
Pods/IQKeyboardToolbarManager/README.md
generated
Normal file
@ -0,0 +1,134 @@
|
||||
# IQKeyboardToolbarManager
|
||||
|
||||
[](https://travis-ci.org/hackiftekhar/IQKeyboardToolbarManager)
|
||||
[](https://cocoapods.org/pods/IQKeyboardToolbarManager)
|
||||
[](https://cocoapods.org/pods/IQKeyboardToolbarManager)
|
||||
[](https://cocoapods.org/pods/IQKeyboardToolbarManager)
|
||||
|
||||

|
||||
|
||||
## Example
|
||||
|
||||
To run the example project, clone the repo, and run `pod install` from the Example directory first.
|
||||
|
||||
## Requirements
|
||||
|
||||
## Installation
|
||||
|
||||
### Swift Package Manager (Recommended)
|
||||
|
||||
IQKeyboardToolbarManager is available through [Swift Package Manager](https://swift.org/package-manager/).
|
||||
|
||||
**Requirements:** iOS 13.0+, Swift 5.7+
|
||||
|
||||
#### Using Xcode:
|
||||
1. In Xcode, go to `File` → `Add Package Dependencies...`
|
||||
2. Enter the repository URL: `https://github.com/hackiftekhar/IQKeyboardToolbarManager`
|
||||
3. Select the version rule (e.g., "Up to Next Major Version")
|
||||
4. Click `Add Package`
|
||||
5. Select the `IQKeyboardToolbarManager` library and click `Add Package`
|
||||
|
||||
#### Using Package.swift:
|
||||
Add the following dependency to your `Package.swift` file:
|
||||
|
||||
```swift
|
||||
dependencies: [
|
||||
.package(url: "https://github.com/hackiftekhar/IQKeyboardToolbarManager", from: "1.1.3")
|
||||
]
|
||||
```
|
||||
|
||||
Then add `IQKeyboardToolbarManager` to your target dependencies:
|
||||
|
||||
```swift
|
||||
.target(
|
||||
name: "YourTarget",
|
||||
dependencies: ["IQKeyboardToolbarManager"]
|
||||
)
|
||||
```
|
||||
|
||||
### CocoaPods
|
||||
|
||||
IQKeyboardToolbarManager is also available through [CocoaPods](https://cocoapods.org). To install
|
||||
it, simply add the following line to your Podfile:
|
||||
|
||||
```ruby
|
||||
pod 'IQKeyboardToolbarManager'
|
||||
```
|
||||
|
||||
### Carthage
|
||||
|
||||
Add the following line to your `Cartfile`:
|
||||
|
||||
```
|
||||
github "hackiftekhar/IQKeyboardToolbarManager"
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
After adding IQKeyboardToolbarManager to your project, import it and enable toolbar handling in AppDelegate:
|
||||
|
||||
```swift
|
||||
import UIKit
|
||||
import IQKeyboardToolbarManager
|
||||
|
||||
@UIApplicationMain
|
||||
class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
|
||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
||||
IQKeyboardToolbarManager.shared.isEnabled = true
|
||||
return true
|
||||
}
|
||||
```
|
||||
|
||||
Cuistomize Behavior
|
||||
```swift
|
||||
IQKeyboardToolbarManager.shared.toolbarConfiguration.useTextInputViewTintColor = true
|
||||
IQKeyboardToolbarManager.shared.toolbarConfiguration.tintColor = UIColor.systemGreen
|
||||
IQKeyboardToolbarManager.shared.toolbarConfiguration.barTintColor = UIColor.systemYellow
|
||||
IQKeyboardToolbarManager.shared.toolbarConfiguration.previousNextDisplayMode = .alwaysShow
|
||||
IQKeyboardToolbarManager.shared.toolbarConfiguration.manageBehavior = .byPosition
|
||||
|
||||
IQKeyboardToolbarManager.shared.toolbarConfiguration.previousBarButtonConfiguration = ... // BarButton configuration to change title, image or system image etc
|
||||
IQKeyboardToolbarManager.shared.toolbarConfiguration.nextBarButtonConfiguration = ... // BarButton configuration to change title, image or system image etc
|
||||
IQKeyboardToolbarManager.shared.toolbarConfiguration.doneBarButtonConfiguration = ... // BarButton configuration to change title, image or system image etc
|
||||
|
||||
IQKeyboardToolbarManager.shared.toolbarConfiguration.placeholderConfiguration.showPlaceholder = false
|
||||
IQKeyboardToolbarManager.shared.toolbarConfiguration.placeholderConfiguration.font = UIFont.italicSystemFont(ofSize: 14)
|
||||
IQKeyboardToolbarManager.shared.toolbarConfiguration.placeholderConfiguration.color = UIColor.systemPurple
|
||||
IQKeyboardToolbarManager.shared.toolbarConfiguration.placeholderConfiguration.buttonColor = UIColor.systemBrown // This is used only if placeholder is an action button
|
||||
|
||||
IQKeyboardToolbarManager.shared.playInputClicks = false
|
||||
|
||||
IQKeyboardToolbarManager.shared.disabledToolbarClasses.append(ChatViewController.self)
|
||||
IQKeyboardToolbarManager.shared.enabledToolbarClasses.append(LoginViewController.self)
|
||||
IQKeyboardToolbarManager.shared.deepResponderAllowedContainerClasses.append(UIStackView.self)
|
||||
```
|
||||
|
||||
Useful functions and variables
|
||||
```swift
|
||||
if IQKeyboardToolbarManager.shared.canGoPrevious {
|
||||
...
|
||||
}
|
||||
|
||||
if IQKeyboardToolbarManager.shared.canGoNext {
|
||||
...
|
||||
}
|
||||
|
||||
IQKeyboardToolbarManager.shared.goPrevious()
|
||||
IQKeyboardToolbarManager.shared.goNext()
|
||||
|
||||
IQKeyboardToolbarManager.shared.reloadInputViews() // If some textInputView hierarchy are changed on the fly then use this to reload button states
|
||||
```
|
||||
|
||||
Useful functions and variables for TextInputView
|
||||
```swift
|
||||
textField.iq.ignoreSwitchingByNextPrevious = false
|
||||
```
|
||||
|
||||
## Author
|
||||
|
||||
Iftekhar Qurashi hack.iftekhar@gmail.com
|
||||
|
||||
## License
|
||||
|
||||
IQKeyboardToolbarManager is available under the MIT license. See the LICENSE file for more info.
|
||||
Reference in New Issue
Block a user