mirror of
https://github.com/vector-im/element-ios.git
synced 2024-09-30 00:02:47 +00:00
139 lines
4.4 KiB
Swift
139 lines
4.4 KiB
Swift
|
//
|
||
|
// Copyright 2021 New Vector Ltd
|
||
|
//
|
||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
// you may not use this file except in compliance with the License.
|
||
|
// You may obtain a copy of the License at
|
||
|
//
|
||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||
|
//
|
||
|
// Unless required by applicable law or agreed to in writing, software
|
||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
// See the License for the specific language governing permissions and
|
||
|
// limitations under the License.
|
||
|
//
|
||
|
|
||
|
import SwiftUI
|
||
|
|
||
|
struct UIKitTextInputConfiguration {
|
||
|
var keyboardType: UIKeyboardType = .default
|
||
|
var returnKeyType: UIReturnKeyType = .default
|
||
|
var isSecureTextEntry: Bool = false
|
||
|
var autocapitalizationType: UITextAutocapitalizationType = .sentences
|
||
|
var autocorrectionType: UITextAutocorrectionType = .default
|
||
|
}
|
||
|
|
||
|
@available(iOS 14.0, *)
|
||
|
struct ThemableTextField: UIViewRepresentable {
|
||
|
|
||
|
@Environment(\.theme) private var theme: ThemeSwiftUI
|
||
|
|
||
|
@State var placeholder: String?
|
||
|
@Binding var text: String
|
||
|
@State var configuration: UIKitTextInputConfiguration = UIKitTextInputConfiguration()
|
||
|
var onEditingChanged: ((_ edit: Bool) -> Void)?
|
||
|
var onCommit: (() -> Void)?
|
||
|
|
||
|
private let textField: UITextField = UITextField()
|
||
|
private let internalParams = InternalParams()
|
||
|
|
||
|
func makeUIView(context: Context) -> UITextField {
|
||
|
textField.delegate = context.coordinator
|
||
|
textField.setContentHuggingPriority(.defaultHigh, for: .vertical)
|
||
|
textField.setContentHuggingPriority(.defaultLow, for: .horizontal)
|
||
|
textField.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
|
||
|
textField.text = text
|
||
|
|
||
|
textField.addTarget(context.coordinator, action: #selector(Coordinator.textFieldEditingChanged(sender:)), for: .editingChanged)
|
||
|
|
||
|
ResponderManager.register(view: textField)
|
||
|
|
||
|
if internalParams.isFirstResponder {
|
||
|
textField.becomeFirstResponder()
|
||
|
}
|
||
|
|
||
|
return textField
|
||
|
}
|
||
|
|
||
|
func updateUIView(_ uiView: UITextField, context: Context) {
|
||
|
uiView.backgroundColor = .clear
|
||
|
uiView.font = UIFont.preferredFont(forTextStyle: .callout)
|
||
|
uiView.textColor = UIColor(theme.colors.primaryContent)
|
||
|
uiView.tintColor = UIColor(theme.colors.accent)
|
||
|
|
||
|
if uiView.text != self.text {
|
||
|
uiView.text = self.text
|
||
|
}
|
||
|
uiView.placeholder = placeholder
|
||
|
|
||
|
uiView.keyboardType = configuration.keyboardType
|
||
|
uiView.returnKeyType = configuration.returnKeyType
|
||
|
uiView.isSecureTextEntry = configuration.isSecureTextEntry
|
||
|
uiView.autocapitalizationType = configuration.autocapitalizationType
|
||
|
uiView.autocorrectionType = configuration.autocorrectionType
|
||
|
}
|
||
|
|
||
|
static func dismantleUIView(_ uiView: UITextField, coordinator: Coordinator) {
|
||
|
ResponderManager.unregister(view: uiView)
|
||
|
}
|
||
|
|
||
|
// MARK: - Private
|
||
|
|
||
|
private func replaceText(with newText: String) {
|
||
|
self.text = newText
|
||
|
}
|
||
|
|
||
|
// MARK: - Coordinator
|
||
|
|
||
|
func makeCoordinator() -> Coordinator {
|
||
|
return Coordinator(self)
|
||
|
}
|
||
|
|
||
|
class Coordinator: NSObject, UITextFieldDelegate {
|
||
|
|
||
|
var parent: ThemableTextField
|
||
|
|
||
|
init(_ parent: ThemableTextField) {
|
||
|
self.parent = parent
|
||
|
}
|
||
|
|
||
|
func textFieldDidBeginEditing(_ textField: UITextField) {
|
||
|
parent.onEditingChanged?(true)
|
||
|
}
|
||
|
|
||
|
func textFieldDidEndEditing(_ textField: UITextField) {
|
||
|
parent.onEditingChanged?(false)
|
||
|
}
|
||
|
|
||
|
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
|
||
|
if !ResponderManager.makeActiveNextResponder(of: textField) {
|
||
|
textField.resignFirstResponder()
|
||
|
}
|
||
|
|
||
|
parent.onCommit?()
|
||
|
|
||
|
return true
|
||
|
}
|
||
|
|
||
|
@objc func textFieldEditingChanged(sender: UITextField) {
|
||
|
parent.replaceText(with: sender.text ?? "")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private class InternalParams {
|
||
|
var isFirstResponder = false
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
// MARK: - modifiers
|
||
|
|
||
|
@available(iOS 14.0, *)
|
||
|
extension ThemableTextField {
|
||
|
func makeFirstResponder() -> ThemableTextField {
|
||
|
internalParams.isFirstResponder = true
|
||
|
return self
|
||
|
}
|
||
|
}
|