// // NotificationPresenter.swift // PrivadoVPN // // Created by Juraldinio on 3/28/21. // Copyright © 2021 Privado LLC. All rights reserved. // import Foundation struct NotificationAction { enum Action: String { case outPeriod = "OUT_PERIOD" case outTraffic = "OUT_TRAFFIC" } let action: Action let urlPath: String? } struct NotificationLocal { enum Kind { case calendar case interval case location } enum Action: String { case passReset = "PASSRESET" case conlimit = "CONNLIMIT" } let subject: String let date: Date let kind: Kind let actions: [String] let title: String let body: String let isVPNActive: Bool let loginUrlPath: String? let trafficTotalMb: UInt let trafficLeftMb: UInt let localIp: String? } protocol NotificationModuleOutput: AnyObject { var scheduler: Emitter<[NotificationLocal]> { get } // func navigate(to route: Route) func closeNotifications() // func notification(with actions: [NotificationAction]) // func deliver(notifications: [NotificationLocal]) } protocol NotificationModuleInput: AnyObject { var hasUnreadEmitter: Emitter { get } } final class NotificationPresenter: NotificationControllerOutput, NotificationModuleInput { private weak var output: NotificationModuleOutput? private let interactor: NotificationInteractorInput private let customerModule: CustomerModuleInput weak var viewInput: NotificationControllerInput? // MARK: - Init init(interactor: NotificationInteractorInput, customer: CustomerModuleInput, output: NotificationModuleOutput?) { self.interactor = interactor self.customerModule = customer self.output = output self.bind() } // MARK: - Private func bind() { self.interactor.serviceReceiving.addReaction { [weak self] receiving -> ShouldContinueReceiveNotifications in guard let self = self else { return false } guard receiving , self.customerModule.customer.isExist else { return true } self.customerModule .requireCustomerInfo() .onFinish() return true } self.interactor.notificationsEmitter.addReaction { [weak self] notifications -> ShouldContinueReceiveNotifications in let actions = notifications.map { notification -> [NotificationAction] in let actions = notification.actions.compactMap { NotificationAction.Action(rawValue: $0) } return actions.map { NotificationAction(action: $0, urlPath: notification.urlPath) } }.reduce([], +) self?.output?.notification(with: actions) return self.isExist } self.interactor.localNotificationsEmitter.addReaction { [weak self] notifications -> ShouldContinueReceiveNotifications in let localNotifications = notifications.map { NotificationLocal(subject: $0.subject, date: $0.sentDate, kind: .interval, actions: $0.actions, title: $0.subject, body: $0.body, isVPNActive: $0.isVpnActive, loginUrlPath: $0.urlPath, trafficTotalMb: $0.trafficTotalMb, trafficLeftMb: $0.trafficLeftMb, localIp: $0.localIp) } self?.output?.scheduler.invoke(localNotifications) return self.isExist } } // MARK: - NotificationControllerOutput func notificationListReady(_ view: NotificationControllerInput) { view.refreshView(exists: self.interactor.notifications.count > 0) if !self.interactor.notifications.isEmpty { self.interactor.ungear() } } func notificationLostClose(_ view: NotificationControllerInput) { self.output?.closeNotifications() } func notificationEmptyMessage(_ view: NotificationControllerInput) -> String { NSLocalizedString("notifications.list.empty", comment: "") } func notificationRecordsCount(in view: NotificationControllerInput) -> Int { self.interactor.notifications.count } func notificationRecord(in view: NotificationControllerInput, at index: Int) -> NotificationCellModel? { guard let model = self.interactor.notifications[safe: index] else { return nil } return NotificationCellModel(title: model.subject, sentDate: model.sentDate, body: model.body) } func viewDidAppear() { self.hasUnreadEmitter.invoke(false) } // MARK: - NotificationModuleInput var hasUnreadEmitter: Emitter { self.interactor.hasUnreadEmitter } }