๐Ÿ‘”TimerView

Combine โŸฉ Timer โŸฉ TimerView

// 2022.03.24: refactored to be more flexible

// ------------------------------------------------------
// โญ๏ธ ๆฝ›่—ๅ•้กŒ๏ผš
//    ๅฆ‚ๆžœๅŒๆ™‚ไฝฟ็”จๅ…ฉๅ€‹ TimerView๏ผŒtimer ็ซŸ็„ถไธๆ˜ฏๅ„่‡ช็จ็ซ‹โ“
//    ( ๐Ÿ‘‰ ๅƒ็œ‹๏ผšใ€Œ๐Ÿ‘๏ธ ้ ่ฆฝใ€)
// ------------------------------------------------------

import SwiftUI
import Combine

/// ๐Ÿ‘” TimerView
/// ```
/// TimerView(every: 1) { ... }
/// TimerView(every: 1, update: { time in ... }) { ... }
/// ```
struct TimerView<Content: View>: View {
    
    // โญ๏ธ time interval on which to publish events
    var interval: TimeInterval = 1
    
    // โญ๏ธ update with time
    var update: (Date) -> Void = { _ in }
    
    // โญ๏ธ generate timer content
    @ViewBuilder var content: () -> Content 
    
    // โญ๏ธ timer that fires on the main thread.
    let timer: Publishers.Autoconnect<Timer.TimerPublisher>
        
    // init
    init(
        every interval: TimeInterval, 
        update: @escaping (Date) -> Void = {_ in},     // default: do nothing
        @ViewBuilder content: @escaping () -> Content
    ) {
        self.content = content
        self.update = update
        self.timer = Timer
            .publish(every: interval, on: .main, in: .common)
            .autoconnect()    // โญ๏ธ auto-connect when subscribed
    }
    
    // โญ๏ธ detect whether app has gone background
    @Environment(\.scenePhase) private var scenePhase
    @State private var isActive = true
    
    var body: some View {
        content()
            // โญ๏ธ whenever `timer` fires, update with time
            .onReceive(timer) { time in
                // โญ๏ธ if app goes background, stop updating immediately.
                guard isActive else { return }
                // โญ๏ธ update with time
                update(time)
            }
            // โญ๏ธ mark the app inactive once it goes background.
            .onChange(of: scenePhase) { newPhase in
                isActive = (newPhase == .active)
            }
    }
}

History

  1. 2022.03.24

Last updated