123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687 |
- import UIKit
- import DcCore
- protocol ProgressAlertHandler: UIViewController {
- var progressAlert: UIAlertController? { get set } // needs to be implemented as weak
- var progressObserver: NSObjectProtocol? { get set } // set to nil in viewDidDisappear
- func showProgressAlert(title: String, dcContext: DcContext)
- func updateProgressAlertValue(value: Int?)
- func updateProgressAlert(error: String?)
- func updateProgressAlertSuccess(completion: VoidFunction?)
- func addProgressAlertListener(progressName: Notification.Name, onSuccess: @escaping VoidFunction)
- }
- extension ProgressAlertHandler {
- func showProgressAlert(title: String, dcContext: DcContext) {
- let progressAlert = makeProgressAlert(dcContext: dcContext)
- progressAlert.actions[0].isEnabled = true
- progressAlert.title = title
- progressAlert.message = String.localized("one_moment")
- self.present(progressAlert, animated: true, completion: nil)
- self.progressAlert = progressAlert
- }
- private func makeProgressAlert(dcContext: DcContext) -> UIAlertController {
- let alert = UIAlertController(title: "", message: "", preferredStyle: .alert)
- alert.addAction(UIAlertAction(
- title: String.localized("cancel"),
- style: .cancel,
- handler: { _ in
- dcContext.stopOngoingProcess()
- }))
- return alert
- }
- func updateProgressAlertValue(value: Int?) {
- if let value = value {
- progressAlert?.message = String.localized("one_moment") + " " + String(value/10) + "%"
- }
- }
- func updateProgressAlert(error message: String?) {
- DispatchQueue.main.async(execute: {
- // CAVE: show the new alert in the dismiss-done-handler of the previous one -
- // otherwise we get the error "Attempt to present <UIAlertController: ...> while a presentation is in progress."
- // and the error won't be shown.
- // (when animated is true, that works also sequentially, however better not rely on that, also we do not want an animation here)
- self.progressAlert?.dismiss(animated: false) {
- let errorAlert = UIAlertController(title: String.localized("error"), message: message, preferredStyle: .alert)
- errorAlert.addAction(UIAlertAction(title: String.localized("ok"), style: .default, handler: nil))
- self.present(errorAlert, animated: true, completion: nil)
- }
- })
- }
- func updateProgressAlertSuccess(completion onComplete: VoidFunction?) {
- updateProgressAlertValue(value: 1000)
- // delay so the user has time to read the success message
- DispatchQueue.main.asyncAfter(deadline: .now() + 1, execute: {
- self.progressAlert?.dismiss(animated: true) {
- onComplete?()
- }
- })
- }
- func addProgressAlertListener(progressName: Notification.Name, onSuccess: @escaping VoidFunction) {
- let nc = NotificationCenter.default
- progressObserver = nc.addObserver(
- forName: progressName,
- object: nil,
- queue: nil
- ) { [weak self] notification in
- guard let self = self else { return }
- if let ui = notification.userInfo {
- if ui["error"] as? Bool ?? false {
- DcContext.shared.maybeStartIo()
- self.updateProgressAlert(error: ui["errorMessage"] as? String)
- } else if ui["done"] as? Bool ?? false {
- DcContext.shared.maybeStartIo()
- self.updateProgressAlertSuccess(completion: onSuccess)
- } else {
- self.updateProgressAlertValue(value: ui["progress"] as? Int)
- }
- }
- }
- }
- }
|