import Cocoa
-fileprivate enum State: Int {
- case none = 0
- case hasMission = 1
- case finish = 2
- case earlyReturn = 3
+protocol MissionStatusObserver: class {
+
+ func didUpdate(state: MissionStatus)
}
-class MissionStatus: NSObject {
- private let number: Int
- private let controller: NSArrayController
- private var didNotify = false
- private var realTime: TimeInterval = 0.0 {
- didSet { time = realTime as NSNumber }
+protocol DeckMissionObserverDelegate: class {
+
+ func didChangeState(deck: Deck)
+}
+
+final class DeckMissionObserver {
+
+ private let deck: Deck
+ private var observation: NSKeyValueObservation?
+
+ weak var delegate: DeckMissionObserverDelegate? {
+
+ didSet {
+ delegate?.didChangeState(deck: deck)
+ }
+ }
+
+ init(deck: Deck) {
+
+ self.deck = deck
+
+ observation = deck.observe(\Deck.mission_2) { _, _ in
+ self.delegate?.didChangeState(deck: deck)
+ }
}
- dynamic var name: String?
- dynamic var time: NSNumber?
- dynamic var state: NSNumber?
- dynamic var missionId: NSNumber? {
- didSet { updateState() }
+}
+
+final class MissionStatus: NSObject {
+
+ private enum State: Int {
+
+ case none = 0
+ case hasMission = 1
+ case finish = 2
+ case earlyReturn = 3
+
+ case unknown = 999999
+ }
+
+ static func valid(number: Int) -> Bool {
+
+ return 2...4 ~= number
+ }
+
+ let number: Int
+ private let observer: DeckMissionObserver
+
+ private(set) var name: String?
+ private(set) var time: TimeInterval?
+
+ private var state: State = .unknown
+ private var rawState: Int = 0 {
+
+ didSet {
+ state = State(rawValue: rawState) ?? .unknown
+ }
}
+ private var missionId: Int = 0
+ private var milliseconds: Int = 0
+ private var fleetName: String = ""
+
+ private var didNotify = false
+
+ weak var delegate: MissionStatusObserver?
+ /// CAUTION: 初回起動時/マスタ更新時にはデータがないので失敗する
init?(number: Int) {
- guard (2...4).contains(number) else { return nil }
+
+ guard MissionStatus.valid(number: number) else { return nil }
+
self.number = number
- controller = NSArrayController()
+
+ guard let deck = ServerDataStore.default.deck(by: number) else { return nil }
+ self.observer = DeckMissionObserver(deck: deck)
+
super.init()
- controller.managedObjectContext = ServerDataStore.default.managedObjectContext
- controller.entityName = Entity.deck.name
- controller.fetchPredicate = NSPredicate(format: "id = %ld", number)
- controller.automaticallyRearrangesObjects = true
- controller.fetch(nil)
-
- bind("state", to: controller, withKeyPath: "selection.mission_0")
- bind("missionId", to: controller, withKeyPath: "selection.mission_1")
+
+ observer.delegate = self
}
private func updateState() {
- guard let stat = State(rawValue: state as! Int)
- else { return print("unknown State") }
- if stat == .none || stat == .finish {
- if stat == .none { didNotify = false }
+
+ switch state {
+
+ case .none, .finish:
+ didNotify = false
name = nil
time = nil
- return
+
+ case .hasMission, .earlyReturn:
+ name = ServerDataStore.default.masterMission(by: missionId)?.name ?? "Unknown"
+
+ case .unknown:
+ Logger.shared.log("unknown State")
}
- guard let missionId = self.missionId as? Int
- else { return }
- guard let mission = ServerDataStore.default.masterMission(by: missionId)
- else {
- name = "Unknown"
- DispatchQueue(label: "MissionStatus")
- .asyncAfter(deadline: .now() + 0.33) {
- self.updateState()
- }
- return
- }
- name = mission.name
+ delegate?.didUpdate(state: self)
}
+}
+
+extension MissionStatus: DockInformationUpdater {
func update() {
- if name == nil {
- time = nil
- return
- }
- guard let t = controller.value(forKeyPath: "selection.mission_2") as? Int
- else {
- name = nil
- time = nil
- return
+
+ defer {
+ delegate?.didUpdate(state: self)
}
- let compTime = TimeInterval(Int(t / 1_000))
- let now = Date()
- let diff = compTime - now.timeIntervalSince1970
- if diff < 0 { realTime = 0 }
- else { realTime = diff }
+ guard let name = name else { return }
+
+ let compTime = TimeInterval(Int(milliseconds / 1_000))
+ let diff = compTime - Date().timeIntervalSince1970
+
+ // set to 0. if diff is less than 0.
+ time = max(0, diff)
+ // notify UserNotification.
if didNotify { return }
if diff >= 1 * 60 { return }
- guard let fleetName = controller.value(forKeyPath: "selection.name") as? String
- else { return }
let notification = NSUserNotification()
- let format = NSLocalizedString("%@ Will Return From Mission.", comment: "%@ Will Return From Mission.")
+ let format = LocalizedStrings.missionWillReturnMessage.string
notification.title = String(format: format, fleetName)
- let txtFormat = NSLocalizedString("%@ Will Return From %@.", comment: "%@ Will Return From %@.")
- notification.informativeText = String(format: txtFormat, fleetName, name!)
- if UserDefaults.standard.playFinishMissionSound {
+ let txtFormat = LocalizedStrings.missionWillReturnInformation.string
+ notification.informativeText = String(format: txtFormat, fleetName, name)
+
+ if UserDefaults.standard[.playFinishMissionSound] {
+
notification.soundName = NSUserNotificationDefaultSoundName
}
+
NSUserNotificationCenter.default.deliver(notification)
+
didNotify = true
}
}
+
+extension MissionStatus: DeckMissionObserverDelegate {
+
+ func didChangeState(deck: Deck) {
+
+ rawState = deck.mission_0
+ missionId = deck.mission_1
+ milliseconds = deck.mission_2
+ fleetName = deck.name
+
+ updateState()
+ }
+}