move from own implementation of Repeat to the 3d-party library

This commit is contained in:
Serhiy Mytrovtsiy
2020-04-29 11:59:03 +02:00
parent a2f39d75b5
commit 903dad9a86
11 changed files with 19 additions and 438 deletions

View File

@@ -1,2 +1,3 @@
github "danielgindi/Charts" ~> 3.4.0
github "ashleymills/Reachability.swift" ~> 5.0.0
github "ashleymills/Reachability.swift" ~> 5.0.0
github "malcommac/Repeat" ~> 0.6.0

View File

@@ -1,2 +1,3 @@
github "ashleymills/Reachability.swift" "v5.0.0"
github "danielgindi/Charts" "v3.4.0"
github "danielgindi/Charts" "v3.5.0"
github "malcommac/Repeat" "0.6.0"

View File

@@ -10,7 +10,6 @@
9A09C8A222B3D94D0018426F /* BatteryWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A09C8A122B3D94D0018426F /* BatteryWidget.swift */; };
9A1410F9229E721100D29793 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A1410F8229E721100D29793 /* AppDelegate.swift */; };
9A141100229E721200D29793 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9A1410FE229E721200D29793 /* Main.storyboard */; };
9A2D15D023C77BA300C4C417 /* Repeater.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A2D15CF23C77BA300C4C417 /* Repeater.swift */; };
9A2D15D223CCEC7600C4C417 /* Module.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A2D15D123CCEC7600C4C417 /* Module.swift */; };
9A2D15D523CCEFF700C4C417 /* CPU.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A2D15D423CCEFF700C4C417 /* CPU.swift */; };
9A2D15D723CCFE1B00C4C417 /* CPULoadReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A2D15D623CCFE1B00C4C417 /* CPULoadReader.swift */; };
@@ -53,6 +52,8 @@
9A6CFC0122A1C9F5001E782D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 9A6CFC0022A1C9F5001E782D /* Assets.xcassets */; };
9A74D59722B44498004FE1FA /* Mini.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A74D59622B44498004FE1FA /* Mini.swift */; };
9A79B36A22D3BEE600BF1C3A /* Widget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A79B36922D3BEE600BF1C3A /* Widget.swift */; };
9A7DE036245982460084BD7A /* Repeat.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9A7DE035245982460084BD7A /* Repeat.framework */; };
9A7DE037245982460084BD7A /* Repeat.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9A7DE035245982460084BD7A /* Repeat.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
9AA28DC1243774ED00D2B196 /* Sensors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9AA28DC0243774ED00D2B196 /* Sensors.swift */; };
9AA28DC32437752D00D2B196 /* SensorsMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9AA28DC22437752D00D2B196 /* SensorsMenu.swift */; };
9AA28DD1243799E500D2B196 /* SensorsWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9AA28DD0243799E500D2B196 /* SensorsWidget.swift */; };
@@ -78,6 +79,7 @@
dstSubfolderSpec = 10;
files = (
9A5349CF23D8832E00C23824 /* Reachability.framework in Embed Frameworks */,
9A7DE037245982460084BD7A /* Repeat.framework in Embed Frameworks */,
9A6698E62326AB16001D00E1 /* Charts.framework in Embed Frameworks */,
);
name = "Embed Frameworks";
@@ -102,7 +104,6 @@
9A1410F8229E721100D29793 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
9A1410FF229E721200D29793 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
9A141101229E721200D29793 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
9A2D15CF23C77BA300C4C417 /* Repeater.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Repeater.swift; sourceTree = "<group>"; };
9A2D15D123CCEC7600C4C417 /* Module.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Module.swift; sourceTree = "<group>"; };
9A2D15D423CCEFF700C4C417 /* CPU.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CPU.swift; sourceTree = "<group>"; };
9A2D15D623CCFE1B00C4C417 /* CPULoadReader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CPULoadReader.swift; sourceTree = "<group>"; };
@@ -146,6 +147,7 @@
9A6CFC0022A1C9F5001E782D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
9A74D59622B44498004FE1FA /* Mini.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Mini.swift; sourceTree = "<group>"; };
9A79B36922D3BEE600BF1C3A /* Widget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Widget.swift; sourceTree = "<group>"; };
9A7DE035245982460084BD7A /* Repeat.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Repeat.framework; path = Carthage/Build/Mac/Repeat.framework; sourceTree = "<group>"; };
9A998CD722A199920087ADE7 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
9A998CD922A199970087ADE7 /* ServiceManagement.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ServiceManagement.framework; path = System/Library/Frameworks/ServiceManagement.framework; sourceTree = SDKROOT; };
9AA28DC0243774ED00D2B196 /* Sensors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Sensors.swift; sourceTree = "<group>"; };
@@ -171,6 +173,7 @@
buildActionMask = 2147483647;
files = (
9A5349CE23D8832E00C23824 /* Reachability.framework in Frameworks */,
9A7DE036245982460084BD7A /* Repeat.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -328,7 +331,6 @@
9A5B1CC4229E7B40008B9D3C /* Extensions.swift */,
9A426DB722C2B5EE00C064C4 /* MacAppUpdater.swift */,
9A59AE55231EE02F007989D6 /* ChartMarker.swift */,
9A2D15CF23C77BA300C4C417 /* Repeater.swift */,
9A3434F0243E19E6006B19F9 /* LaunchAtLogin.swift */,
);
path = libs;
@@ -350,6 +352,7 @@
9A998CD622A199920087ADE7 /* Frameworks */ = {
isa = PBXGroup;
children = (
9A7DE035245982460084BD7A /* Repeat.framework */,
9A5349CD23D8832E00C23824 /* Reachability.framework */,
9A6698E32326AAE5001D00E1 /* Charts.framework */,
9A998CD922A199970087ADE7 /* ServiceManagement.framework */,
@@ -564,7 +567,6 @@
9A57A18522A1D26D0033E318 /* MenuBar.swift in Sources */,
9A2D15D923CD036400C4C417 /* CPUMenu.swift in Sources */,
9AF6F1FE231D732600B8E1E4 /* PopupViewController.swift in Sources */,
9A2D15D023C77BA300C4C417 /* Repeater.swift in Sources */,
9A1410F9229E721100D29793 /* AppDelegate.swift in Sources */,
9A2D15E823CE29A400C4C417 /* RAMMenu.swift in Sources */,
9A2D15DB23CD0B2100C4C417 /* CPUPopup.swift in Sources */,
@@ -756,7 +758,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.13;
MARKETING_VERSION = 1.6.2;
MARKETING_VERSION = 1.6.3;
PRODUCT_BUNDLE_IDENTIFIER = eu.exelban.Stats;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@@ -787,7 +789,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.13;
MARKETING_VERSION = 1.6.2;
MARKETING_VERSION = 1.6.3;
PRODUCT_BUNDLE_IDENTIFIER = eu.exelban.Stats;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";

View File

@@ -8,6 +8,7 @@
import Cocoa
import IOKit.ps
import Repeat
class Battery: Module {
public var name: String = "Battery"

View File

@@ -8,6 +8,7 @@
import Cocoa
import Charts
import Repeat
class CPU: Module {
public var name: String = "CPU"

View File

@@ -7,6 +7,7 @@
//
import Cocoa
import Repeat
class Disk: Module {
public var name: String = "SSD"

View File

@@ -8,6 +8,7 @@
import Cocoa
import Charts
import Repeat
protocol Module: class {
var name: String { get } // module name

View File

@@ -8,6 +8,7 @@
import Cocoa
import Charts
import Repeat
class Network: Module {
public var name: String = "Network"

View File

@@ -8,6 +8,7 @@
import Cocoa
import Charts
import Repeat
class RAM: Module {
public var name: String = "RAM"

View File

@@ -7,6 +7,7 @@
//
import Cocoa
import Repeat
class Sensors: Module {
public var name: String = "Sensors"

View File

@@ -1,430 +0,0 @@
//
// Repeat
// A modern alternative to NSTimer made in GCD with debouncer and throttle
// -----------------------------------------------------------------------
// Created by: Daniele Margutti
// hello@danielemargutti.com
// http://www.danielemargutti.com
//
// Twitter: @danielemargutti
//
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import Foundation
open class Repeater: Equatable {
/// State of the timer
///
/// - paused: idle (never started yet or paused)
/// - running: timer is running
/// - executing: the observers are being executed
/// - finished: timer lifetime is finished
public enum State: Equatable, CustomStringConvertible {
case paused
case running
case executing
case finished
public static func == (lhs: State, rhs: State) -> Bool {
switch (lhs, rhs) {
case (.paused, .paused),
(.running, .running),
(.executing, .executing),
(.finished, .finished):
return true
default:
return false
}
}
/// Return `true` if timer is currently running, including when the observers are being executed.
public var isRunning: Bool {
guard self == .running || self == .executing else { return false }
return true
}
/// Return `true` if the observers are being executed.
public var isExecuting: Bool {
guard case .executing = self else { return false }
return true
}
/// Is timer finished its lifetime?
/// It return always `false` for infinite timers.
/// It return `true` for `.once` mode timer after the first fire,
/// and when `.remainingIterations` is zero for `.finite` mode timers
public var isFinished: Bool {
guard case .finished = self else { return false }
return true
}
/// State description
public var description: String {
switch self {
case .paused: return "idle/paused"
case .finished: return "finished"
case .running: return "running"
case .executing: return "executing"
}
}
}
/// Repeat interval
public enum Interval {
case nanoseconds(_: Int)
case microseconds(_: Int)
case milliseconds(_: Int)
case minutes(_: Int)
case seconds(_: Double)
case hours(_: Int)
case days(_: Int)
internal var value: DispatchTimeInterval {
switch self {
case .nanoseconds(let value): return .nanoseconds(value)
case .microseconds(let value): return .microseconds(value)
case .milliseconds(let value): return .milliseconds(value)
case .seconds(let value): return .milliseconds(Int( Double(value) * Double(1000)))
case .minutes(let value): return .seconds(value * 60)
case .hours(let value): return .seconds(value * 3600)
case .days(let value): return .seconds(value * 86400)
}
}
}
/// Mode of the timer.
///
/// - infinite: infinite number of repeats.
/// - finite: finite number of repeats.
/// - once: single repeat.
public enum Mode {
case infinite
case finite(_: Int)
case once
/// Is timer a repeating timer?
internal var isRepeating: Bool {
switch self {
case .once: return false
default: return true
}
}
/// Number of repeats, if applicable. Otherwise `nil`
public var countIterations: Int? {
switch self {
case .finite(let counts): return counts
default: return nil
}
}
/// Is infinite timer
public var isInfinite: Bool {
guard case .infinite = self else {
return false
}
return true
}
}
/// Handler typealias
public typealias Observer = ((Repeater) -> Void)
/// Token assigned to the observer
public typealias ObserverToken = UInt64
/// Current state of the timer
public private(set) var state: State = .paused {
didSet {
self.onStateChanged?(self, state)
}
}
/// Callback called to intercept state's change of the timer
public var onStateChanged: ((_ timer: Repeater, _ state: State) -> Void)?
/// List of the observer of the timer
private var observers = [ObserverToken: Observer]()
/// Next token of the timer
private var nextObserverID: UInt64 = 0
/// Internal GCD Timer
private var timer: DispatchSourceTimer?
/// Is timer a repeat timer
public private(set) var mode: Mode
/// Number of remaining repeats count
public private(set) var remainingIterations: Int?
/// Interval of the timer
private var interval: Interval
/// Accuracy of the timer
private var tolerance: DispatchTimeInterval
/// Dispatch queue parent of the timer
private var queue: DispatchQueue?
/// Initialize a new timer.
///
/// - Parameters:
/// - interval: interval of the timer
/// - mode: mode of the timer
/// - tolerance: tolerance of the timer, 0 is default.
/// - queue: queue in which the timer should be executed; if `nil` a new queue is created automatically.
/// - observer: observer
public init(interval: Interval, mode: Mode = .infinite, tolerance: DispatchTimeInterval = .nanoseconds(0), queue: DispatchQueue? = nil, observer: @escaping Observer) {
self.mode = mode
self.interval = interval
self.tolerance = tolerance
self.remainingIterations = mode.countIterations
self.queue = (queue ?? DispatchQueue(label: "com.repeat.queue"))
self.timer = configureTimer()
self.observe(observer)
}
/// Add new a listener to the timer.
///
/// - Parameter callback: callback to call for fire events.
/// - Returns: token used to remove the handler
@discardableResult
public func observe(_ observer: @escaping Observer) -> ObserverToken {
var (new, overflow) = self.nextObserverID.addingReportingOverflow(1)
if overflow { // you need to add an incredible number of offset...sure you can't
self.nextObserverID = 0
new = 0
}
self.nextObserverID = new
self.observers[new] = observer
return new
}
/// Remove an observer of the timer.
///
/// - Parameter id: id of the observer to remove
public func remove(observer identifier: ObserverToken) {
self.observers.removeValue(forKey: identifier)
}
/// Remove all observers of the timer.
///
/// - Parameter stopTimer: `true` to also stop timer by calling `pause()` function.
public func removeAllObservers(thenStop stopTimer: Bool = false) {
self.observers.removeAll()
if stopTimer {
self.pause()
}
}
/// Configure a new timer session.
///
/// - Returns: dispatch timer
private func configureTimer() -> DispatchSourceTimer {
let associatedQueue = (queue ?? DispatchQueue(label: "com.repeat.\(NSUUID().uuidString)"))
let timer = DispatchSource.makeTimerSource(queue: associatedQueue)
let repeatInterval = interval.value
let deadline: DispatchTime = (DispatchTime.now() + repeatInterval)
if self.mode.isRepeating {
timer.schedule(deadline: deadline, repeating: repeatInterval, leeway: tolerance)
} else {
timer.schedule(deadline: deadline, leeway: tolerance)
}
timer.setEventHandler { [weak self] in
if let unwrapped = self {
unwrapped.timeFired()
}
}
return timer
}
/// Destroy current timer
private func destroyTimer() {
self.timer?.setEventHandler(handler: nil)
self.timer?.cancel()
if state == .paused || state == .finished {
self.timer?.resume()
}
}
/// Create and schedule a timer that will call `handler` once after the specified time.
///
/// - Parameters:
/// - interval: interval delay for single fire
/// - queue: destination queue, if `nil` a new `DispatchQueue` is created automatically.
/// - observer: handler to call when timer fires.
/// - Returns: timer instance
@discardableResult
public class func once(after interval: Interval, tolerance: DispatchTimeInterval = .nanoseconds(0), queue: DispatchQueue? = nil, _ observer: @escaping Observer) -> Repeater {
let timer = Repeater(interval: interval, mode: .once, tolerance: tolerance, queue: queue, observer: observer)
timer.start()
return timer
}
/// Create and schedule a timer that will fire every interval optionally by limiting the number of fires.
///
/// - Parameters:
/// - interval: interval of fire
/// - count: a non `nil` and > 0 value to limit the number of fire, `nil` to set it as infinite.
/// - queue: destination queue, if `nil` a new `DispatchQueue` is created automatically.
/// - handler: handler to call on fire
/// - Returns: timer
@discardableResult
public class func every(_ interval: Interval, count: Int? = nil, tolerance: DispatchTimeInterval = .nanoseconds(0), queue: DispatchQueue? = nil, _ handler: @escaping Observer) -> Repeater {
let mode: Mode = (count != nil ? .finite(count!) : .infinite)
let timer = Repeater(interval: interval, mode: mode, tolerance: tolerance, queue: queue, observer: handler)
timer.start()
return timer
}
/// Force fire.
///
/// - Parameter pause: `true` to pause after fire, `false` to continue the regular firing schedule.
public func fire(andPause pause: Bool = false) {
self.timeFired()
if pause == true {
self.pause()
}
}
/// Reset the state of the timer, optionally changing the fire interval.
///
/// - Parameters:
/// - interval: new fire interval; pass `nil` to keep the latest interval set.
/// - restart: `true` to automatically restart the timer, `false` to keep it stopped after configuration.
public func reset(_ interval: Interval?, restart: Bool = true) {
if self.state.isRunning {
self.setPause(from: self.state)
}
// For finite counter we want to also reset the repeat count
if case .finite(let count) = self.mode {
self.remainingIterations = count
}
// Create a new instance of timer configured
if let newInterval = interval {
self.interval = newInterval
} // update interval
self.destroyTimer()
self.timer = configureTimer()
self.state = .paused
if restart {
self.timer?.resume()
self.state = .running
}
}
/// Start timer. If timer is already running it does nothing.
@discardableResult
public func start() -> Bool {
guard self.state.isRunning == false else {
return false
}
// If timer has not finished its lifetime we want simply
// restart it from the current state.
guard self.state.isFinished == true else {
self.state = .running
self.timer?.resume()
return true
}
// Otherwise we need to reset the state based upon the mode
// and start it again.
self.reset(nil, restart: true)
return true
}
/// Pause a running timer. If timer is paused it does nothing.
@discardableResult
public func pause() -> Bool {
guard state != .paused && state != .finished else {
return false
}
return self.setPause(from: self.state)
}
/// Pause a running timer optionally changing the state with regard to the current state.
///
/// - Parameters:
/// - from: the state which the timer should only be paused if it is the current state
/// - to: the new state to change to if the timer is paused
/// - Returns: `true` if timer is paused
@discardableResult
private func setPause(from currentState: State, to newState: State = .paused) -> Bool {
guard self.state == currentState else {
return false
}
self.timer?.suspend()
self.state = newState
return true
}
/// Called when timer is fired
private func timeFired() {
self.state = .executing
if case .finite = self.mode {
self.remainingIterations! -= 1
}
// dispatch to observers
self.observers.values.forEach { $0(self) }
// manage lifetime
switch self.mode {
case .once:
// once timer's lifetime is finished after the first fire
// you can reset it by calling `reset()` function.
self.setPause(from: .executing, to: .finished)
case .finite:
// for finite intervals we decrement the left iterations count...
if self.remainingIterations! == 0 {
// ...if left count is zero we just pause the timer and stop
self.setPause(from: .executing, to: .finished)
}
case .infinite:
// infinite timer does nothing special on the state machine
break
}
}
deinit {
self.observers.removeAll()
self.destroyTimer()
}
public static func == (lhs: Repeater, rhs: Repeater) -> Bool {
return lhs === rhs
}
}