132 lines
3.4 KiB
Swift
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
|
|
)
|
|
}
|