// // CommonViewAlert.swift // Wallet // // Created by Igor on 27.02.2021. // Copyright © 2021 AM. All rights reserved. // import UIKit extension UIAlertAction { static let cancel = custom(title: L10n.Common.Button.cancel, style: .cancel) static let ok = custom(title: L10n.Common.Button.ok, style: .cancel) static let no = custom(title: L10n.Common.Button.no, style: .cancel) static func custom( title: String, style: Style = .default, _ action: (() -> Void)? = nil ) -> UIAlertAction { .init(title: title, style: style, handler: { _ in action?() }) } static func yes(_ completion: (() -> Void)? = nil) -> UIAlertAction { .custom(title: L10n.Common.Button.yes) { completion?() } } static func delete(_ completion: (() -> Void)? = nil) -> UIAlertAction { .custom(title: L10n.Common.Button.delete) { completion?() } } } enum Alert { private static var timer: Timer? private static var topWindow: UIWindow? { if #available(iOS 16.0, *), let topWindow = UIApplication.shared.windows.last { return topWindow } else { return UIApplication.shared.windows.first } } static func system( title: String? = nil, text: String? = nil, actions: [UIAlertAction] = [.ok], style: UIAlertController.Style = .alert, in parent: UIViewController = .topController() ) { guard actions.count > 0 else { return } let ctrl = UIAlertController(title: title, message: text, preferredStyle: style) actions.forEach({ ctrl.addAction($0) }) DispatchQueue.main.async { parent.present(ctrl, animated: true) } } static func custom(image: UIImage, text: String, color: UIColor, _ action: @escaping () -> Void, timerTime: Double = 3) { timer?.invalidate() timer = nil if let view = Self.topWindow?.subviews.compactMap({ $0 as? CommonViewAlert }).first { view.action = action view.imgView.image = image view.textLbl.attributedText = text.attributed(style: .regular, size: 16, color: color, alignment: .center) let width = view.textLbl.frameX + 12 var size = view.textLbl.sizeThatFits(.init(width: UIScreen.main.bounds.width - 24 - width, height: 300)) size.width += width size.height = min(max(28, size.height), 250) + 24 UIView.animate(withDuration: Animation.fast) { view.frame = .init(x: 12, y: 40, width: UIScreen.main.bounds.width - 24, height: size.height) } } else { let view = CommonViewAlert(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width - 24, height: 52)) view.action = action view.imgView.image = image view.textLbl.attributedText = text.attributed(style: .regular, size: 16, color: color, alignment: .center) let width = view.textLbl.frameX + 12 var size = view.textLbl.sizeThatFits(.init(width: UIScreen.main.bounds.width - 24 - width, height: 300)) size.width += width size.height = min(max(28, size.height), 250) + 24 view.frame = .init( x: 12, y: -size.height, width: UIScreen.main.bounds.width - 24, height: size.height ) Self.topWindow?.addSubview(view) UIView.animate(withDuration: Animation.fast) { view.frame = .init(x: 12, y: 40, width: UIScreen.main.bounds.width - 24, height: view.frame.height) } } timer = delayed(timerTime) { Alert.hide() } } static func notify(_ error: Error?) { error == nil ? success() : self.error(error) } static func notify(_ error: Error?, dismiss: UIViewController, animated: Bool = true, _ completion: (() -> Void)? = nil) { error == nil ? success() : self.error(error) if error == nil { dismiss.dismiss(animated: true, completion: completion) } } static func notify(_ error: Error?, pop: UIViewController, animated: Bool = true, _ completion: (() -> Void)? = nil) { error == nil ? success() : self.error(error) if error == nil { pop.navigationController?.popViewController(animated: true) if let completion = completion { delayed(.medium, completion) } } } static func success(text: String = L10n.Common.Alert.success) { DispatchQueue.main.async { custom(image: Asset.commonAlertSuccess.image, text: text, color: Asset.textForest.color) { Alert.hide() } } } static func error(_ error: Error? = nil) { if let error = error { if error.localizedDescription.contains("insufficient ram") { let field: UIView = .field( title: "", text: "common.alert.ram.text".localized, textStyle: "regular_16" ) let content = RamActionsView() var localizedError = error.localizedDescription if let language = Locale.preferredLanguages.first, language.lowercased().starts(with: "ru") { localizedError = localizedError.localizedRamError } content.update(text: localizedError) let confirmButton: UIView = .button(style: .primary, title: "common.alert.ram.buy.button".localized) { var service: Resources.Service.Popup.Statistics? let account = Accounts().current?.name service = .init(account: account ?? "") let vc = StoryboardScene.Resources.ram.instantiate() vc.action = .buy vc.performance = service UIViewController.topController().dismiss(animated: true) { UIViewController().mainController.content.push(vc, animated: true) } } let bottomButton: UIView = .button(style: .tertiary, title: "common.alert.ram.what.button".localized) { UIViewController.topController().dismiss(animated: true) { let vc = RamDescriptionViewController() UIViewController().mainController.content.push(vc, animated: true) } } UIViewController.topController().dismiss(animated: true) { Popup.show(title: "common.alert.ram.title".localized, views: [field, content, confirmButton, bottomButton]) } } else if let error = error as? BlockchainError { switch error { case .lackOfResources(let description): self.error(text: description) case .commonError(let description): self.error(text: description) } } else { self.error(text: error.localizedDescription) } } } static func error(text: String = L10n.Common.Alert.error, delay: Double = 0) { DispatchQueue.main.asyncAfter(deadline: .now() + delay, execute: { custom(image: Asset.commonAlertFailed.image, text: text, color: Asset.textBrick.color) { Alert.hide() Popup.show(title: L10n.Common.Alert.error, description: text, submit: L10n.Common.Button.ok) } }) } static func hint(text: String = L10n.Common.Alert.hint) { custom(image: Asset.commonAlertSuccess.image, text: text, color: Asset.textForest.color) { Alert.hide() } } static func copy(_ message: String?) { guard let message = message else { return } UIPasteboard.general.string = message hint(text: L10n.Common.Alert.copied) } static func copy(_ image: UIImage?) { guard let image = image else { return } UIPasteboard.general.image = image hint(text: L10n.Common.Alert.copied) } static func refresh() { guard let view = Self.topWindow?.subviews.compactMap({ $0 as? CommonViewAlert }).first else { return } view.superview?.bringSubviewToFront(view) } private static func hide(_ completion: (() -> Void)? = nil) { timer?.invalidate() timer = nil guard let view = Self.topWindow?.subviews.compactMap({ $0 as? CommonViewAlert }).first else { return } UIView.animate(withDuration: .fast) { view.frame = .init( x: (UIScreen.main.bounds.width - view.frame.width)/2, y: -view.frame.height, width: view.frame.width, height: view.frame.height ) } completion: { _ in view.removeFromSuperview() completion?() } } } class CommonViewAlert: CommonViewCustom { @IBOutlet weak var imgView: UIImageView! @IBOutlet weak var textLbl: UILabel! var containerView: UIView? { (self.contentView as? CommonViewContainer)?.contentView } var action: (() -> Void)? // init(action: (() -> Void)? = nil) { // super.init(frame: .init(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 52)) // self.action = action // } // required init?(coder aDecoder: NSCoder) { // super.init(frame: .init(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 52)) // } @IBAction func onAction(_: AnyObject?) { action?() } }