Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Add dark mode to your apps. #potatotips / add dark mode to your apps

fromkk
May 15, 2019

Add dark mode to your apps. #potatotips / add dark mode to your apps

potatotips #61にて発表したきたものです。
# Typeにダークモードを追加したのでその考え方と方法、ライブラリとして書き出した( https://github.com/fromkk/ColorSet )の宣伝です。

fromkk

May 15, 2019
Tweet

More Decks by fromkk

Other Decks in Programming

Transcript

  1. "EEEBSLNPEFUPZPVSBQQT
    QPUBUPUJQT,B[VZB6FPLB!GSPNLL

    View full-size slide

  2. 1SPpMF
    struct Profile {
    let name = "Kazuya Ueoka"
    let twitter = "@fromkk"
    let github = "fromkk"
    let qiita = "fromkk"
    let company = "Timers Inc."
    }

    2

    View full-size slide

  3. %BSLNPEF ❓

    View full-size slide

  4. *BEEFEEBSLNPEFGFBUVSFUP# Type

    View full-size slide

  5. )PXUPJNQMFNFOU

    View full-size slide

  6. *GZPVBSFVTJOH3Y4XJGU ZPVDBOJNQMFNFOUFBTJMZ
    import UIKit
    import RxSwift
    import RxCocoa
    struct ColorSet {
    static var backgroundColor = BehaviorRelay(value: defaultBackgroundColor)
    static var theme = BehaviorRelay(value: defaultThemeColor)
    }
    // Bind background color
    ColorSet.backgroundColor.bind(to: view.rx.backgroundColor).disposed(by: disposeBag)


    // Change background color
    ColorSet.backgroundColor.accept(backgroundColorDark)

    View full-size slide

  7. # Type isn’t using RxSwift

    View full-size slide

  8. *USJFEJNQMFNFOUXJUI1VSF4XJGU

    View full-size slide

  9. TU$SFBUFPCTFSWBUJPO
    import Foundation
    public class ColorObservation: Equatable {
    private let observation: NSObjectProtocol
    weak var notificationCenter: NotificationCenter?
    init(_ observation: NSObjectProtocol, notificationCenter: NotificationCenter) {
    self.observation = observation
    self.notificationCenter = notificationCenter
    }
    public func unregister() {
    notificationCenter?.removeObserver(observation)
    }
    public func append(to observationBag: ColorObservationBag) {
    observationBag.add(self)
    }
    public static func == (lhs: ColorObservation, rhs: ColorObservation) -> Bool {
    return lhs.observation.isEqual(rhs.observation) &&
    (lhs.notificationCenter?.isEqual(rhs.notificationCenter) ?? false)
    }
    }

    View full-size slide

  10. OE4UPSFPCTFSWBUJPOTUPCBH
    import Foundation
    public class ColorObservationBag {
    var observations: [ColorObservation] = []
    public init() {}
    deinit {
    observations.forEach { observation in
    observation.unregister()
    }
    observations = []
    }
    public func add(_ observation: ColorObservation) {
    observations.append(observation)
    }
    public func remove(_ observation: ColorObservation) {
    guard let index = observations.firstIndex(of: observation) else { return }
    observation.unregister()
    observations.remove(at: index)
    }
    }

    View full-size slide

  11. SE$SFBUF0CTFSWBCMF
    public class ColorObservable {
    let didChange: Notification.Name = .init("me.fromkk.ColorSet.didChange")
    let notificationCenter: NotificationCenter = .init()
    public private(set) var value: UIColor {
    didSet {
    notificationCenter.post(name: didChange, object: value)
    }
    }
    public init(_ value: UIColor) {
    self.value = value
    }
    /// Change color
    ///
    /// - Parameter value: Color
    public func accept(_ value: UIColor) {
    self.value = value
    }
    }

    View full-size slide

  12. UI*NQMFNFOUTTVCTDSJCFBOECJOE
    extension ColorObservable {
    public func subscribe(_ callback: @escaping (UIColor) -> Void) -> ColorObservation {
    callback(value)
    return ColorObservation(
    notificationCenter.addObserver(forName: didChange, object: nil, queue: .main, using: { notification in
    guard let value = notification.object as? UIColor else { return }
    callback(value)
    }),
    notificationCenter: notificationCenter
    )
    }
    public func bind(to object: O, keyPath: ReferenceWritableKeyPath) -> ColorObservation {
    return subscribe { [weak object] value in
    object?[keyPath: keyPath] = value
    }
    }
    public func bind(to object: O, keyPath: ReferenceWritableKeyPath) -> ColorObservation {
    return subscribe { [weak object] value in
    object?[keyPath: keyPath] = value
    }
    }
    }

    View full-size slide

  13. )PXUPVTF
    %FpOFZPVSDPMPSTFU

    View full-size slide

  14. )PXUPVTF
    #JOEDPMPSUPZPVSQSPQFSUZ
    class ViewController: UIViewController {
    @IBOutlet var label: UILabel!
    @IBOutlet var darkmodeSwitch: UISwitch!
    let observationBag = ColorObservationBag()
    override func viewDidLoad() {
    super.viewDidLoad()
    MyColorSet.backgroundColor.bind(to: view, keyPath: \.backgroundColor).append(to: observationBag)
    MyColorSet.textColor.bind(to: label, keyPath: \.textColor).append(to: observationBag)
    MyColorSet.textColor.subscribe { [weak self] color in
    self?.label.layer.borderColor = color.cgColor
    }.append(to: observationBag)
    }
    @IBAction func darkmodeSwitchDidChanged(_ sender: UISwitch) {
    if sender.isOn {
    MyColorSet.replace(DarkColorSet.self)
    } else {
    MyColorSet.replace(DefaultColorSet.self)
    }
    }
    }

    View full-size slide

  15. *NBEF$PMPS4FUBT044MJCSBSZ
    IUUQTHJUIVCDPNGSPNLL$PMPS4FU
    (JNFNFBTUBS⭐

    View full-size slide

  16. 8SBQVQ
    w *EFWFMPQFETNBMMMJCSBSZPGTQFDJBMJ[FEDPMPSCJOEJOH
    w -FU`THFUSFBEZUPP⒏DJBMEBSLNPEF(

    View full-size slide

  17. • αʔόʔαΠυΤϯδχΞ (PHP, Golang, AWS)
    • AndroidΤϯδχΞ (Kotlin)
    • iOSΤϯδχΞ (Swift)
    TimersͰ͸ݱࡏΤϯδχΞશ৬छ࠾༻தʂ

    ৄ͘͠͸”Timers”Ͱݕࡧ

    View full-size slide