Reset the elapsed seconds after processing for the RecordingViewModel view model in the Recording package target.
This commit is contained in:
@@ -17,11 +17,11 @@ extension RecordingView {
|
|||||||
var state: State = .notRecording
|
var state: State = .notRecording
|
||||||
|
|
||||||
/// The number of seconds spent recording, excluding any time spent paused.
|
/// The number of seconds spent recording, excluding any time spent paused.
|
||||||
private(set) var secondsElapsed: Int = 0
|
private(set) var elapsedSeconds: Int = 0
|
||||||
|
|
||||||
/// The task that increments ``secondsElapsed`` every second while recording.
|
/// The task that increments ``elapsedSeconds`` every second while recording.
|
||||||
@ObservationIgnored
|
@ObservationIgnored
|
||||||
private var timerTask: Task<Void, Never>?
|
private var taskTimer: Task<Void, Never>?
|
||||||
|
|
||||||
// MARK: Computed
|
// MARK: Computed
|
||||||
|
|
||||||
@@ -65,7 +65,7 @@ extension RecordingView {
|
|||||||
/// The elapsed recording time, formatted as `mm:ss` for the timer label.
|
/// The elapsed recording time, formatted as `mm:ss` for the timer label.
|
||||||
var textTimer: String {
|
var textTimer: String {
|
||||||
Duration
|
Duration
|
||||||
.seconds(secondsElapsed)
|
.seconds(elapsedSeconds)
|
||||||
.formatted(.time(pattern: .minuteSecond(padMinuteToLength: 2)))
|
.formatted(.time(pattern: .minuteSecond(padMinuteToLength: 2)))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,7 +112,7 @@ extension RecordingView {
|
|||||||
///
|
///
|
||||||
/// Starts the timer when a recording begins or resumes, stops it in every other state, and kicks off ``processInput()`` when the input is sent.
|
/// Starts the timer when a recording begins or resumes, stops it in every other state, and kicks off ``processInput()`` when the input is sent.
|
||||||
///
|
///
|
||||||
/// - Parameter shouldRestartTimer: Whether ``secondsElapsed`` should be reset to zero before the timer starts, which is the case for
|
/// - Parameter shouldRestartTimer: Whether ``elapsedSeconds`` should be reset to zero before the timer starts, which is the case for
|
||||||
/// a new recording as opposed to one resuming from a pause.
|
/// a new recording as opposed to one resuming from a pause.
|
||||||
func updatedState(
|
func updatedState(
|
||||||
shouldRestartTimer: Bool
|
shouldRestartTimer: Bool
|
||||||
@@ -140,9 +140,9 @@ private extension RecordingView.Model {
|
|||||||
|
|
||||||
// MARK: Methods
|
// MARK: Methods
|
||||||
|
|
||||||
/// Processes the recorded input, returning the model to the not-recording state when finished.
|
/// Processes the recorded input, resetting ``elapsedSeconds`` and returning the model to the not-recording state when finished.
|
||||||
///
|
///
|
||||||
/// Currently a placeholder that simulates the work with a five-second delay.
|
/// Currently a placeholder that simulates the work with a two-second delay.
|
||||||
func processInput() async {
|
func processInput() async {
|
||||||
guard state == .processing else {
|
guard state == .processing else {
|
||||||
return
|
return
|
||||||
@@ -150,21 +150,22 @@ private extension RecordingView.Model {
|
|||||||
|
|
||||||
try? await Task.sleep(for: .seconds(2))
|
try? await Task.sleep(for: .seconds(2))
|
||||||
|
|
||||||
|
elapsedSeconds = 0
|
||||||
state = .notRecording
|
state = .notRecording
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Starts the timer task, which increments ``secondsElapsed`` once per second until it is cancelled. Any previously running timer task is cancelled first.
|
/// Starts the timer task, which increments ``elapsedSeconds`` once per second until it is cancelled. Any previously running timer task is cancelled first.
|
||||||
///
|
///
|
||||||
/// - Parameter shouldRestartTimer: Whether ``secondsElapsed`` should be reset to zero before the timer starts.
|
/// - Parameter shouldRestartTimer: Whether ``elapsedSeconds`` should be reset to zero before the timer starts.
|
||||||
func startTimer(
|
func startTimer(
|
||||||
_ shouldRestartTimer: Bool
|
_ shouldRestartTimer: Bool
|
||||||
) {
|
) {
|
||||||
if shouldRestartTimer {
|
if shouldRestartTimer {
|
||||||
secondsElapsed = 0
|
elapsedSeconds = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
timerTask?.cancel()
|
taskTimer?.cancel()
|
||||||
timerTask = Task { [weak self] in
|
taskTimer = Task { [weak self] in
|
||||||
while !Task.isCancelled {
|
while !Task.isCancelled {
|
||||||
try? await Task.sleep(for: .seconds(1))
|
try? await Task.sleep(for: .seconds(1))
|
||||||
|
|
||||||
@@ -172,15 +173,15 @@ private extension RecordingView.Model {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
self.secondsElapsed += 1
|
self.elapsedSeconds += 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Stops the timer task, if any, keeping ``secondsElapsed`` at its current value.
|
/// Stops the timer task, if any, keeping ``elapsedSeconds`` at its current value.
|
||||||
func stopTimer() {
|
func stopTimer() {
|
||||||
timerTask?.cancel()
|
taskTimer?.cancel()
|
||||||
timerTask = nil
|
taskTimer = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ struct RecordingViewModelTests {
|
|||||||
let model = Model()
|
let model = Model()
|
||||||
|
|
||||||
#expect(model.state == .notRecording)
|
#expect(model.state == .notRecording)
|
||||||
#expect(model.secondsElapsed == 0)
|
#expect(model.elapsedSeconds == 0)
|
||||||
#expect(model.textTimer == "00:00")
|
#expect(model.textTimer == "00:00")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -178,7 +178,7 @@ struct RecordingViewModelTests {
|
|||||||
|
|
||||||
try await Task.sleep(for: .seconds(1.2))
|
try await Task.sleep(for: .seconds(1.2))
|
||||||
|
|
||||||
#expect(model.secondsElapsed >= 1)
|
#expect(model.elapsedSeconds >= 1)
|
||||||
#expect(model.textTimer == "00:01")
|
#expect(model.textTimer == "00:01")
|
||||||
|
|
||||||
model.state = .notRecording
|
model.state = .notRecording
|
||||||
@@ -196,12 +196,12 @@ struct RecordingViewModelTests {
|
|||||||
model.state = .paused
|
model.state = .paused
|
||||||
model.updatedState(shouldRestartTimer: false)
|
model.updatedState(shouldRestartTimer: false)
|
||||||
|
|
||||||
let secondsWhenPaused = model.secondsElapsed
|
let secondsWhenPaused = model.elapsedSeconds
|
||||||
|
|
||||||
try await Task.sleep(for: .seconds(1.2))
|
try await Task.sleep(for: .seconds(1.2))
|
||||||
|
|
||||||
#expect(secondsWhenPaused >= 1)
|
#expect(secondsWhenPaused >= 1)
|
||||||
#expect(model.secondsElapsed == secondsWhenPaused)
|
#expect(model.elapsedSeconds == secondsWhenPaused)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test func `keeps elapsed seconds when resumed`() async throws {
|
@Test func `keeps elapsed seconds when resumed`() async throws {
|
||||||
@@ -215,12 +215,12 @@ struct RecordingViewModelTests {
|
|||||||
model.state = .paused
|
model.state = .paused
|
||||||
model.updatedState(shouldRestartTimer: false)
|
model.updatedState(shouldRestartTimer: false)
|
||||||
|
|
||||||
let secondsWhenPaused = model.secondsElapsed
|
let secondsWhenPaused = model.elapsedSeconds
|
||||||
|
|
||||||
model.state = .recording
|
model.state = .recording
|
||||||
model.updatedState(shouldRestartTimer: false)
|
model.updatedState(shouldRestartTimer: false)
|
||||||
|
|
||||||
#expect(model.secondsElapsed == secondsWhenPaused)
|
#expect(model.elapsedSeconds == secondsWhenPaused)
|
||||||
|
|
||||||
model.state = .notRecording
|
model.state = .notRecording
|
||||||
model.updatedState(shouldRestartTimer: false)
|
model.updatedState(shouldRestartTimer: false)
|
||||||
@@ -240,7 +240,7 @@ struct RecordingViewModelTests {
|
|||||||
model.state = .recording
|
model.state = .recording
|
||||||
model.updatedState(shouldRestartTimer: true)
|
model.updatedState(shouldRestartTimer: true)
|
||||||
|
|
||||||
#expect(model.secondsElapsed == 0)
|
#expect(model.elapsedSeconds == 0)
|
||||||
|
|
||||||
model.state = .notRecording
|
model.state = .notRecording
|
||||||
model.updatedState(shouldRestartTimer: false)
|
model.updatedState(shouldRestartTimer: false)
|
||||||
@@ -254,15 +254,26 @@ struct RecordingViewModelTests {
|
|||||||
@Suite("Processing")
|
@Suite("Processing")
|
||||||
struct Processing {
|
struct Processing {
|
||||||
|
|
||||||
@Test func `returns to not recording`() async throws {
|
@Test func `returns to not recording with a reset timer`() async throws {
|
||||||
let model = Model()
|
let model = Model()
|
||||||
|
|
||||||
|
model.state = .recording
|
||||||
|
model.updatedState(shouldRestartTimer: true)
|
||||||
|
|
||||||
|
try await Task.sleep(for: .seconds(1.2))
|
||||||
|
|
||||||
|
model.state = .paused
|
||||||
|
model.updatedState(shouldRestartTimer: false)
|
||||||
|
|
||||||
|
#expect(model.elapsedSeconds >= 1)
|
||||||
|
|
||||||
model.state = .processing
|
model.state = .processing
|
||||||
model.updatedState(shouldRestartTimer: false)
|
model.updatedState(shouldRestartTimer: false)
|
||||||
|
|
||||||
try await Task.sleep(for: .seconds(2.5))
|
try await Task.sleep(for: .seconds(2.5))
|
||||||
|
|
||||||
#expect(model.state == .notRecording)
|
#expect(model.state == .notRecording)
|
||||||
|
#expect(model.elapsedSeconds == 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user