Added a discard button and error handling to the RecordingView view in the Recording package target.
This commit is contained in:
@@ -51,9 +51,9 @@ public struct RecordingView: View {
|
||||
|
||||
// MARK: Body
|
||||
|
||||
/// The content of the view: the timer label above the main and send buttons, with the transcription of every processed recording
|
||||
/// forwarded to the closure given at initialization, and an alert surfacing any error of the recording flow — offering to open the
|
||||
/// app's settings when the microphone permission was denied.
|
||||
/// The content of the view: the timer label above the main, discard, and send buttons, with the transcription of every processed
|
||||
/// recording forwarded to the closure given at initialization, and an alert surfacing any error of the recording flow — offering to
|
||||
/// open the app's settings when the microphone permission was denied.
|
||||
public var body: some View {
|
||||
VStack(
|
||||
spacing: Constant.Spacing.stack
|
||||
@@ -69,6 +69,8 @@ public struct RecordingView: View {
|
||||
.easeInOut,
|
||||
value: model.textTimer
|
||||
)
|
||||
.accessibilityLabel(Constant.Text.labelTimer)
|
||||
.accessibilityValue(model.textTimerAccessible)
|
||||
}
|
||||
|
||||
GlassEffectContainer {
|
||||
@@ -86,6 +88,21 @@ public struct RecordingView: View {
|
||||
invertStyle: true
|
||||
))
|
||||
.disabled(model.shouldDisableMain)
|
||||
.accessibilityLabel(labelMain)
|
||||
|
||||
if model.shouldShowDiscard {
|
||||
Button {
|
||||
model.pressedDiscard()
|
||||
} label: {
|
||||
Image(systemName: Constant.Symbol.discard)
|
||||
.resizable()
|
||||
.scaledToFit()
|
||||
}
|
||||
.buttonStyle(.recording(
|
||||
invertStyle: true
|
||||
))
|
||||
.accessibilityLabel(Constant.Text.labelDiscard)
|
||||
}
|
||||
|
||||
if model.shouldShowSend {
|
||||
Button {
|
||||
@@ -102,6 +119,7 @@ public struct RecordingView: View {
|
||||
invertStyle: !model.isProcessing
|
||||
))
|
||||
.disabled(model.isProcessing)
|
||||
.accessibilityLabel(labelSend)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -149,6 +167,26 @@ public struct RecordingView: View {
|
||||
|
||||
private extension RecordingView {
|
||||
|
||||
// MARK: Computed
|
||||
|
||||
/// The accessibility label for the main button, matching its action in the current state.
|
||||
var labelMain: String {
|
||||
switch model.state {
|
||||
case .notRecording, .processing: Constant.Text.labelRecord
|
||||
case .recording: Constant.Text.labelPause
|
||||
case .paused: Constant.Text.labelResume
|
||||
}
|
||||
}
|
||||
|
||||
/// The accessibility label for the send button: the sending action while paused, the ongoing processing otherwise.
|
||||
var labelSend: String {
|
||||
model.isProcessing
|
||||
? Constant.Text.labelProcessing
|
||||
: Constant.Text.labelSend
|
||||
}
|
||||
|
||||
// MARK: Methods
|
||||
|
||||
/// Returns the message describing the given error for the alert.
|
||||
///
|
||||
/// - Parameter error: The error to describe.
|
||||
@@ -157,6 +195,7 @@ private extension RecordingView {
|
||||
for error: RecordingError
|
||||
) -> String {
|
||||
switch error {
|
||||
case .assetsUnavailable: Constant.Text.messageAssetsUnavailable
|
||||
case .captureFailed: Constant.Text.messageCaptureFailed
|
||||
case .permissionDenied: Constant.Text.messagePermissionDenied
|
||||
case .transcriptionFailed: Constant.Text.messageTranscriptionFailed
|
||||
@@ -180,6 +219,12 @@ private enum Constant {
|
||||
static let stack: CGFloat = 8
|
||||
}
|
||||
|
||||
/// The symbol constants.
|
||||
enum Symbol {
|
||||
/// The system symbol of the discard button's image.
|
||||
static let discard = "trash"
|
||||
}
|
||||
|
||||
/// The text constants, localized through the package's string catalog.
|
||||
enum Text {
|
||||
/// The title of the alert's dismissal button.
|
||||
@@ -187,11 +232,51 @@ private enum Constant {
|
||||
localized: "view.recording.alert.error.button.ok",
|
||||
bundle: .module
|
||||
)
|
||||
/// The accessibility label of the discard button.
|
||||
static let labelDiscard = String(
|
||||
localized: "view.recording.button.discard.label",
|
||||
bundle: .module
|
||||
)
|
||||
/// The accessibility label of the main button while recording.
|
||||
static let labelPause = String(
|
||||
localized: "view.recording.button.main.label.pause",
|
||||
bundle: .module
|
||||
)
|
||||
/// The accessibility label of the send button while processing.
|
||||
static let labelProcessing = String(
|
||||
localized: "view.recording.button.send.label.processing",
|
||||
bundle: .module
|
||||
)
|
||||
/// The accessibility label of the main button while not recording.
|
||||
static let labelRecord = String(
|
||||
localized: "view.recording.button.main.label.record",
|
||||
bundle: .module
|
||||
)
|
||||
/// The accessibility label of the main button while paused.
|
||||
static let labelResume = String(
|
||||
localized: "view.recording.button.main.label.resume",
|
||||
bundle: .module
|
||||
)
|
||||
/// The accessibility label of the send button while paused.
|
||||
static let labelSend = String(
|
||||
localized: "view.recording.button.send.label.send",
|
||||
bundle: .module
|
||||
)
|
||||
/// The accessibility label of the timer.
|
||||
static let labelTimer = String(
|
||||
localized: "view.recording.timer.label",
|
||||
bundle: .module
|
||||
)
|
||||
/// The title of the alert's button that opens the app's settings.
|
||||
static let buttonSettings = String(
|
||||
localized: "view.recording.alert.error.button.settings",
|
||||
bundle: .module
|
||||
)
|
||||
/// The message describing unavailable speech model assets.
|
||||
static let messageAssetsUnavailable = String(
|
||||
localized: "view.recording.alert.error.message.assets",
|
||||
bundle: .module
|
||||
)
|
||||
/// The message describing a failure of the audio capture.
|
||||
static let messageCaptureFailed = String(
|
||||
localized: "view.recording.alert.error.message.capture",
|
||||
|
||||
Reference in New Issue
Block a user