Skip to content

Instantly share code, notes, and snippets.

@onevcat
Last active October 29, 2020 08:48
Show Gist options
  • Save onevcat/40f21b41a6b1ffa06ceb9f3ee0470bf3 to your computer and use it in GitHub Desktop.
Save onevcat/40f21b41a6b1ffa06ceb9f3ee0470bf3 to your computer and use it in GitHub Desktop.

Revisions

  1. onevcat revised this gist Oct 21, 2020. No changes.
  2. onevcat created this gist Oct 21, 2020.
    132 changes: 132 additions & 0 deletions TrafficLight.swift
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,132 @@
    //: A UIKit based Playground for presenting user interface

    import UIKit
    import PlaygroundSupport

    public protocol TrafficLightOption {
    associatedtype Value

    /// 默认的选项值
    static var defaultValue: Value { get }
    }

    extension TrafficLight {
    public enum GreenLightColor: TrafficLightOption {
    case green
    case turquoise

    public static let defaultValue: GreenLightColor = .green
    }
    }

    extension TrafficLight {
    public var preferredGreenLightColor: TrafficLight.GreenLightColor {
    get { self[option: GreenLightColor.self] }
    set { self[option: GreenLightColor.self] = newValue }
    }
    }

    public class TrafficLight {

    public enum State {
    case stop
    case proceed
    case caution
    }

    private var options = [ObjectIdentifier: Any]()

    public subscript<T: TrafficLightOption>(option type: T.Type) -> T.Value {
    get {
    options[ObjectIdentifier(type)] as? T.Value
    ?? type.defaultValue
    }
    set {
    options[ObjectIdentifier(type)] = newValue
    }
    }

    public private(set) var state: State = .stop {
    didSet { onStateChanged?(state) }
    }

    public var onStateChanged: ((State) -> Void)?

    public var stopDuration = 4.0
    public var proceedDuration = 6.0
    public var cautionDuration = 1.5

    private var timer: Timer?

    public func start() {
    guard timer == nil else { return }
    turnState(.stop)
    }

    public func stop() {
    timer?.invalidate()
    timer = nil
    }

    private func turnState(_ state: State) {
    switch state {
    case .proceed:
    timer = Timer.scheduledTimer(withTimeInterval: proceedDuration, repeats: false) { _ in
    self.turnState(.caution)
    }
    case .caution:
    timer = Timer.scheduledTimer(withTimeInterval: cautionDuration, repeats: false) { _ in
    self.turnState(.stop)
    }
    case .stop:
    timer = Timer.scheduledTimer(withTimeInterval: stopDuration, repeats: false) { _ in
    self.turnState(.proceed)
    }
    }
    self.state = state
    }
    }


    class MyViewController : UIViewController {

    var light: TrafficLight!

    override func loadView() {
    let view = UIView()
    view.backgroundColor = .white
    self.view = view

    light = TrafficLight()
    light.preferredGreenLightColor = .turquoise
    light.onStateChanged = { [weak self, weak light] state in
    guard let self = self, let light = light else { return }
    let color: UIColor
    switch state {
    case .proceed: color = light.preferredGreenLightColor.color
    case .caution: color = .yellow
    case .stop: color = .red
    }
    UIView.animate(withDuration: 0.25) {
    self.view.backgroundColor = color
    }
    }
    light.start()
    }

    deinit {
    light.stop()
    }
    }


    extension TrafficLight.GreenLightColor {
    var color: UIColor {
    switch self {
    case .green: return .green
    case .turquoise: return UIColor(red: 0.25, green: 0.88, blue: 0.82, alpha: 1.00)
    }
    }
    }
    // Present the view controller in the Live View window
    PlaygroundPage.current.liveView = MyViewController()