Defined the RecordingService and the TranscribingService protocols in the Recording package tracker.

This commit is contained in:
2026-07-03 21:33:07 +02:00
parent cc82e4fbf2
commit 31b778a36e
3 changed files with 126 additions and 0 deletions
@@ -0,0 +1,53 @@
import Foundation
/// A service that captures audio from a microphone for the Recording feature.
///
/// ``RecordingView`` attaches the service to its model at initialization, so the audio capture can be swapped without touching the feature's
/// state machine for example, with a real microphone backend in the app, or with a mock in unit tests.
public protocol RecordingService: Sendable {
/// Starts a new audio recording from the microphone.
func start() async throws
/// Pauses the ongoing recording.
func pause() async throws
/// Resumes a paused recording.
func resume() async throws
/// Stops the recording.
///
/// - Returns: The audio captured since the recording started.
func stop() async throws -> Data
}
// MARK: - Services
/// The recording service used by default, which simulates the audio capture without touching a microphone.
public struct SimulatedRecordingService: RecordingService {
// MARK: Initializers
/// Creates a simulated recording service.
public init() {}
// MARK: Methods
/// Simulates the start of an audio recording.
public func start() async throws {}
/// Simulates the pause of an ongoing recording.
public func pause() async throws {}
/// Simulates the resumption of a paused recording.
public func resume() async throws {}
/// Simulates the stop of a recording.
///
/// - Returns: An empty audio payload.
public func stop() async throws -> Data {
.init()
}
}
@@ -0,0 +1,56 @@
import Foundation
/// A service that transcribes recorded audio into text for the Recording feature.
///
/// ``RecordingView`` attaches the service to its model at initialization, so the transcription can be swapped without touching the feature's
/// state machine for example, with a real transcription backend in the app, or with a fast mock in unit tests.
public protocol TranscribingService: Sendable {
/// Transcribes the given recorded audio into text.
///
/// - Parameter audio: The recorded audio to transcribe.
/// - Returns: The transcription of the recorded audio.
func transcribe(_ audio: Data) async throws -> String
}
// MARK: - Services
/// The transcribing service used by default, which simulates the transcription work.
public struct SimulatedTranscribingService: TranscribingService {
// MARK: Initializers
/// Creates a simulated transcribing service.
public init() {}
// MARK: Methods
/// Simulates the transcription of the given recorded audio with a two-second delay.
///
/// - Parameter audio: The recorded audio to transcribe.
/// - Returns: A dummy transcription.
public func transcribe(_ audio: Data) async throws -> String {
try await Task.sleep(for: Constant.Delay.transcribing)
return Constant.Text.transcription
}
}
// MARK: - Constants
/// The constant values used across the transcribing services.
private enum Constant {
/// The delay constants.
enum Delay {
/// The duration of the simulated transcription work.
static let transcribing: Duration = .seconds(2)
}
/// The text constants.
enum Text {
/// The dummy transcription of a recorded audio.
static let transcription = "This is a dummy transcription of the recorded audio."
}
}
+17
View File
@@ -41,6 +41,8 @@ Attendi/
│ ├── RecordingView.swift
│ ├── RecordingViewModel.swift
│ ├── RecordingButtonStyle.swift
│ ├── RecordingService.swift
│ ├── TranscribingService.swift
│ └── Images.xcassets # Record, pause, and send icons
└── Tests/
├── Recording/
@@ -81,6 +83,21 @@ text content transition.
background, shrinks while pressed, and dims while disabled. The label and its padding scale with Dynamic Type
via `@ScaledMetric`, and an `invertStyle` flag controls whether the label's color scheme is inverted for contrast.
### Services
The actual recording work is abstracted behind two protocols, injected into `RecordingView` at initialization and
attached to its view model:
- **`RecordingService`** — captures the audio from a microphone, with throwing async `start`, `pause`, `resume`, and
`stop` methods; `stop` returns the captured audio.
- **`TranscribingService`** — transcribes the captured audio into text through a throwing async `transcribe` method;
the view model stores the result once processing finishes.
The default `SimulatedRecordingService` and `SimulatedTranscribingService` fake the work (the latter with a two-second
delay and a dummy transcription); the unit tests inject fast mocks, and real backends can be plugged in the same way
without touching the feature's state machine. When either service fails, the view model falls back to the
not-recording state.
## Testing
The view model is covered by Swift Testing suites in `RecordingViewModelTests.swift`, grouped with nested `@Suite`