Files
attendi/Widgets/Attendi/Sources/Views/RecordingControls.swift
T

132 lines
3.4 KiB
Swift

import AppIntents
import Commanding
import Recording
import SwiftUI
import WidgetKit
/// The buttons controlling the recording flow through the App Intents the app executes, matching the current state: a pause
/// button while recording; discard, resume, and send buttons while paused; and only a discard button while the recorded input
/// is being processed.
struct RecordingControls: View {
// MARK: Properties
/// The dynamic content of the Live Activity to render.
let state: RecordingActivityAttributes.ContentState
// MARK: Body
var body: some View {
HStack(
spacing: Constant.Spacing.stack
) {
switch state.state {
case .recording:
pauseButton
case .paused:
discardButton
recordButton
processButton
case .processing:
discardButton
}
}
}
}
// MARK: - Subviews
private extension RecordingControls {
// MARK: Computed
/// The discard button, shown while the recording is paused or being processed, that throws the recording away.
var discardButton: some View {
Button(intent: DiscardRecordingIntent()) {
Image.Symbol.discard
.resizable()
}
.buttonStyle(.action(
type: .destructive
))
.accessibilityLabel(Text("view.recording-controls.button.discard"))
}
/// The pause button, shown while recording, that pauses the ongoing recording.
var pauseButton: some View {
Button(intent: ToggleRecordingIntent()) {
Image.Symbol.pause
.resizable()
}
.buttonStyle(.action(
type: .default
))
.accessibilityLabel(Text("view.recording-controls.button.pause"))
}
/// The send button, shown while the recording is paused, that sends it for processing.
var processButton: some View {
Button(intent: ProcessRecordingIntent()) {
Image.Symbol.send
.resizable()
}
.buttonStyle(.action(
type: .confirmative
))
.accessibilityLabel(Text("view.recording-controls.button.send"))
}
/// The resume button, shown while the recording is paused, that resumes it.
var recordButton: some View {
Button(intent: ToggleRecordingIntent()) {
Image.Symbol.microphone
.resizable()
}
.buttonStyle(.action(
type: .default
))
.accessibilityLabel(Text("view.recording-controls.button.resume"))
}
}
// MARK: - Constants
/// The constant values used across the recording Live Activity.
private enum Constant {
/// The spacing constants.
enum Spacing {
/// The spacing between the elements of a stack.
static let stack: CGFloat = 16
}
}
// MARK: - Previews
#Preview(
"Recording Controls view",
as: .content,
using: RecordingActivityAttributes()
) {
RecordingLiveActivity()
} contentStates: {
RecordingActivityAttributes.ContentState(
state: .recording,
anchor: .now,
elapsed: 0
)
RecordingActivityAttributes.ContentState(
state: .paused,
anchor: nil,
elapsed: 42
)
RecordingActivityAttributes.ContentState(
state: .processing,
anchor: nil,
elapsed: 42
)
}