// // TextAlert.swift // StikJIT // // Created by s s on 2025/5/11. // import SwiftUI import UIKit public struct TextFieldAlertModifier: ViewModifier { @State private var alertController: UIAlertController? @Binding var isPresented: Bool let title: String let text: Binding let placeholder: String let action: (String?) -> Void let actionCancel: (String?) -> Void public func body(content: Content) -> some View { content.onChange(of: isPresented) { isPresented in if isPresented, alertController == nil { let alertController = makeAlertController() self.alertController = alertController guard let scene = UIApplication.shared.connectedScenes.first as? UIWindowScene else { return } scene.windows.first?.rootViewController?.present(alertController, animated: true) } else if !isPresented, let alertController = alertController { alertController.dismiss(animated: true) self.alertController = nil } } } private func makeAlertController() -> UIAlertController { let controller = UIAlertController(title: title, message: nil, preferredStyle: .alert) controller.addTextField { $0.placeholder = self.placeholder $0.text = self.text.wrappedValue $0.clearButtonMode = .always } controller.addAction(UIAlertAction(title: "Cancel", style: .cancel) { _ in self.actionCancel(nil) shutdown() }) controller.addAction(UIAlertAction(title: "OK", style: .default) { _ in self.action(controller.textFields?.first?.text) shutdown() }) return controller } private func shutdown() { isPresented = false alertController = nil } } extension View { public func textFieldAlert( isPresented: Binding, title: String, text: Binding, placeholder: String = "", action: @escaping (String?) -> Void, actionCancel: @escaping (String?) -> Void ) -> some View { self.modifier(TextFieldAlertModifier(isPresented: isPresented, title: title, text: text, placeholder: placeholder, action: action, actionCancel: actionCancel)) } }