1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
|
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift open source project
//
// Copyright (c) 2024 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
import _Concurrency
/// A progress animation wrapper that throttles updates to a given interval.
final class ThrottledProgressAnimation: ProgressAnimationProtocol {
private let animation: ProgressAnimationProtocol
private let shouldUpdate: () -> Bool
private var pendingUpdate: (Int, Int, String)?
init<C: Clock>(
_ animation: ProgressAnimationProtocol,
now: @escaping () -> C.Instant, interval: C.Duration, clock: C.Type = C.self
) {
self.animation = animation
var lastUpdate: C.Instant?
self.shouldUpdate = {
let now = now()
if let lastUpdate = lastUpdate, now < lastUpdate.advanced(by: interval) {
return false
}
// If we're over the interval or it's the first update, should update.
lastUpdate = now
return true
}
}
func update(step: Int, total: Int, text: String) {
guard shouldUpdate() else {
pendingUpdate = (step, total, text)
return
}
pendingUpdate = nil
animation.update(step: step, total: total, text: text)
}
func complete(success: Bool) {
if let (step, total, text) = pendingUpdate {
animation.update(step: step, total: total, text: text)
}
animation.complete(success: success)
}
func clear() {
animation.clear()
}
}
@_spi(SwiftPMInternal)
extension ProgressAnimationProtocol {
@_spi(SwiftPMInternal)
public func throttled<C: Clock>(
now: @escaping () -> C.Instant,
interval: C.Duration,
clock: C.Type = C.self
) -> some ProgressAnimationProtocol {
ThrottledProgressAnimation(self, now: now, interval: interval, clock: clock)
}
@_spi(SwiftPMInternal)
public func throttled<C: Clock>(
clock: C,
interval: C.Duration
) -> some ProgressAnimationProtocol {
self.throttled(now: { clock.now }, interval: interval, clock: C.self)
}
@_spi(SwiftPMInternal)
public func throttled(
interval: ContinuousClock.Duration
) -> some ProgressAnimationProtocol {
self.throttled(clock: ContinuousClock(), interval: interval)
}
}
|