Refined the recording Live Activity presentation in the Widget target.
This commit is contained in:
@@ -92,6 +92,7 @@
|
|||||||
Attendi/Catalogs/Localizable.xcstrings,
|
Attendi/Catalogs/Localizable.xcstrings,
|
||||||
Attendi/Sources/Bundle/AttendiWidgetBundle.swift,
|
Attendi/Sources/Bundle/AttendiWidgetBundle.swift,
|
||||||
"Attendi/Sources/Extensions/Image+Symbols.swift",
|
"Attendi/Sources/Extensions/Image+Symbols.swift",
|
||||||
|
"Attendi/Sources/Extensions/RecordingActivityState+Presentation.swift",
|
||||||
Attendi/Sources/Intents/DiscardRecordingIntent.swift,
|
Attendi/Sources/Intents/DiscardRecordingIntent.swift,
|
||||||
Attendi/Sources/Intents/ProcessRecordingIntent.swift,
|
Attendi/Sources/Intents/ProcessRecordingIntent.swift,
|
||||||
Attendi/Sources/Intents/ToggleRecordingIntent.swift,
|
Attendi/Sources/Intents/ToggleRecordingIntent.swift,
|
||||||
|
|||||||
@@ -1,43 +1,124 @@
|
|||||||
{
|
{
|
||||||
"sourceLanguage" : "en",
|
"sourceLanguage" : "en",
|
||||||
"strings" : {
|
"strings" : {
|
||||||
"Configuration" : {
|
"intent.discard-recording.description" : {
|
||||||
|
"comment" : "Description of the Discard Recording App Intent, behind the recording Live Activity's discard button. Shown wherever the system lists the intent, such as Shortcuts and Settings.",
|
||||||
|
"localizations" : {
|
||||||
|
"en" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "Throws the paused recording away."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"Discard" : {
|
"intent.discard-recording.title" : {
|
||||||
|
"comment" : "Title of the Discard Recording App Intent, behind the recording Live Activity's discard button. Shown wherever the system lists the intent, such as Shortcuts and Settings.",
|
||||||
|
"localizations" : {
|
||||||
|
"en" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "Discard Recording"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"Discard Recording" : {
|
"intent.processing-recording.description" : {
|
||||||
|
"comment" : "Description of the Process Recording App Intent, behind the recording Live Activity's send button. Shown wherever the system lists the intent, such as Shortcuts and Settings.",
|
||||||
|
"extractionState" : "manual",
|
||||||
|
"localizations" : {
|
||||||
|
"en" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "Sends the paused recording for processing."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"Favorite Emoji" : {
|
"intent.processing-recording.title" : {
|
||||||
|
"comment" : "Title of the Process Recording App Intent, behind the recording Live Activity's send button. Shown wherever the system lists the intent, such as Shortcuts and Settings.",
|
||||||
|
"extractionState" : "manual",
|
||||||
|
"localizations" : {
|
||||||
|
"en" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "Process Recording"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"Favorite Emoji:" : {
|
"intent.toggle-recording.description" : {
|
||||||
|
"comment" : "Description of the Pause or Resume Recording App Intent, behind the recording Live Activity's main button. Shown wherever the system lists the intent, such as Shortcuts and Settings.",
|
||||||
|
"localizations" : {
|
||||||
|
"en" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "Pauses or resumes the ongoing recording."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"Pause" : {
|
"intent.toggle-recording.title" : {
|
||||||
|
"comment" : "Title of the Pause or Resume Recording App Intent, behind the recording Live Activity's main button. Shown wherever the system lists the intent, such as Shortcuts and Settings.",
|
||||||
|
"localizations" : {
|
||||||
|
"en" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "Pause or Resume Recording"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"Pause or Resume Recording" : {
|
"view.recording-controls.button.discard" : {
|
||||||
|
"comment" : "Accessibility label for the recording Live Activity's discard button, announced by VoiceOver. The button shows only a trash icon.",
|
||||||
|
"extractionState" : "manual",
|
||||||
|
"localizations" : {
|
||||||
|
"en" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "Discard recording"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"Pauses or resumes the ongoing recording." : {
|
"view.recording-controls.button.pause" : {
|
||||||
|
"comment" : "Accessibility label for the recording Live Activity's pause button, announced by VoiceOver. The button shows only a pause icon.",
|
||||||
|
"extractionState" : "manual",
|
||||||
|
"localizations" : {
|
||||||
|
"en" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "Pause recording"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"Resume" : {
|
"view.recording-controls.button.resume" : {
|
||||||
|
"comment" : "Accessibility label for the recording Live Activity's resume button, announced by VoiceOver. The button shows only a microphone icon.",
|
||||||
|
"extractionState" : "manual",
|
||||||
|
"localizations" : {
|
||||||
|
"en" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "Resume recording"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"This is an example widget." : {
|
"view.recording-controls.button.send" : {
|
||||||
|
"comment" : "Accessibility label for the recording Live Activity's send button, which sends the recording for processing. Announced by VoiceOver; the button shows only a send icon.",
|
||||||
},
|
"extractionState" : "manual",
|
||||||
"Throws the paused recording away." : {
|
"localizations" : {
|
||||||
|
"en" : {
|
||||||
},
|
"stringUnit" : {
|
||||||
"Time:" : {
|
"state" : "translated",
|
||||||
|
"value" : "Send recording for processing"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"view.recording-state-label.state.paused" : {
|
"view.recording-state-label.state.paused" : {
|
||||||
|
"comment" : "Status shown in the recording Live Activity while recording is paused.",
|
||||||
"extractionState" : "manual",
|
"extractionState" : "manual",
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"en" : {
|
"en" : {
|
||||||
@@ -49,6 +130,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"view.recording-state-label.state.processing" : {
|
"view.recording-state-label.state.processing" : {
|
||||||
|
"comment" : "Status shown in the recording Live Activity while the recorded audio is being processed.",
|
||||||
"extractionState" : "manual",
|
"extractionState" : "manual",
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"en" : {
|
"en" : {
|
||||||
@@ -60,6 +142,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"view.recording-state-label.state.recording" : {
|
"view.recording-state-label.state.recording" : {
|
||||||
|
"comment" : "Status shown in the recording Live Activity while recording is underway. ",
|
||||||
"extractionState" : "manual",
|
"extractionState" : "manual",
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"en" : {
|
"en" : {
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import WidgetKit
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
import WidgetKit
|
||||||
|
|
||||||
/// The bundle exposing the app's widgets and Live Activities to the system: the ``AttendiWidget`` Home Screen widget and the
|
/// The bundle exposing the app's Live Activities to the system: the ``RecordingLiveActivity`` that surfaces the recording flow on the
|
||||||
/// ``RecordingLiveActivity`` that surfaces the recording flow.
|
/// Lock Screen and in the Dynamic Island.
|
||||||
@main
|
@main
|
||||||
struct AttendiWidgetBundle: WidgetBundle {
|
struct AttendiWidgetBundle: WidgetBundle {
|
||||||
|
|
||||||
/// The widgets and Live Activities the bundle exposes.
|
/// The Live Activities the bundle exposes.
|
||||||
var body: some Widget {
|
var body: some Widget {
|
||||||
RecordingLiveActivity()
|
RecordingLiveActivity()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
import Commanding
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
extension RecordingActivityState {
|
||||||
|
|
||||||
|
// MARK: Computed
|
||||||
|
|
||||||
|
/// The system symbol marking the state in the Live Activity: a microphone while recording, a pause symbol while paused, and
|
||||||
|
/// a send symbol while the recorded input is being processed.
|
||||||
|
var symbol: Image {
|
||||||
|
switch self {
|
||||||
|
case .recording: Image.Symbol.microphone
|
||||||
|
case .paused: Image.Symbol.pause
|
||||||
|
case .processing: Image.Symbol.send
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The tint coloring the state's ``symbol``: yellow while recording or paused, and green while the recorded input is being
|
||||||
|
/// processed.
|
||||||
|
var tint: Color {
|
||||||
|
switch self {
|
||||||
|
case .recording, .paused: .yellow
|
||||||
|
case .processing: .green
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import Commanding
|
|
||||||
import AppIntents
|
import AppIntents
|
||||||
|
import Commanding
|
||||||
|
|
||||||
/// The intent behind the discard button of the recording Live Activity, which throws the recording away.
|
/// The intent behind the discard button of the recording Live Activity, which throws the recording away.
|
||||||
///
|
///
|
||||||
@@ -10,9 +10,14 @@ struct DiscardRecordingIntent: LiveActivityIntent {
|
|||||||
|
|
||||||
// MARK: Constants
|
// MARK: Constants
|
||||||
|
|
||||||
static let title: LocalizedStringResource = "Discard Recording"
|
/// The localized title of the intent, resolved from the widget target's string catalog and shown wherever the system surfaces
|
||||||
static let description = IntentDescription("Throws the paused recording away.")
|
/// the intent.
|
||||||
static let openAppWhenRun = false
|
static let title: LocalizedStringResource = "intent.discard-recording.title"
|
||||||
|
/// The localized description of the intent, resolved from the widget target's string catalog.
|
||||||
|
static let description = IntentDescription("intent.discard-recording.description")
|
||||||
|
/// Whether running the intent brings the app to the foreground; `true`, so discarding the recording opens the app from the
|
||||||
|
/// Live Activity.
|
||||||
|
static let openAppWhenRun = true
|
||||||
|
|
||||||
// MARK: Methods
|
// MARK: Methods
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import Commanding
|
|
||||||
import AppIntents
|
import AppIntents
|
||||||
|
import Commanding
|
||||||
|
|
||||||
/// The intent behind the send button of the recording Live Activity, which sends the paused recording for processing.
|
/// The intent behind the send button of the recording Live Activity, which sends the paused recording for processing.
|
||||||
///
|
///
|
||||||
@@ -10,9 +10,14 @@ struct ProcessRecordingIntent: LiveActivityIntent {
|
|||||||
|
|
||||||
// MARK: Constants
|
// MARK: Constants
|
||||||
|
|
||||||
static let title: LocalizedStringResource = "Process Recording"
|
/// The localized title of the intent, resolved from the widget target's string catalog and shown wherever the system surfaces
|
||||||
static let description = IntentDescription("Sends the paused recording for processing.")
|
/// the intent.
|
||||||
static let openAppWhenRun = false
|
static let title: LocalizedStringResource = "intent.processing-recording.title"
|
||||||
|
/// The localized description of the intent, resolved from the widget target's string catalog.
|
||||||
|
static let description = IntentDescription("intent.processing-recording.description")
|
||||||
|
/// Whether running the intent brings the app to the foreground; `true`, so sending the recording for processing opens the app
|
||||||
|
/// from the Live Activity.
|
||||||
|
static let openAppWhenRun = true
|
||||||
|
|
||||||
// MARK: Methods
|
// MARK: Methods
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import Commanding
|
|
||||||
import AppIntents
|
import AppIntents
|
||||||
|
import Commanding
|
||||||
|
|
||||||
/// The intent behind the main button of the recording Live Activity, which pauses or resumes the recording.
|
/// The intent behind the main button of the recording Live Activity, which pauses or resumes the recording.
|
||||||
///
|
///
|
||||||
@@ -10,8 +10,13 @@ struct ToggleRecordingIntent: LiveActivityIntent {
|
|||||||
|
|
||||||
// MARK: Constants
|
// MARK: Constants
|
||||||
|
|
||||||
static let title: LocalizedStringResource = "Pause or Resume Recording"
|
/// The localized title of the intent, resolved from the widget target's string catalog and shown wherever the system surfaces
|
||||||
static let description = IntentDescription("Pauses or resumes the ongoing recording.")
|
/// the intent.
|
||||||
|
static let title: LocalizedStringResource = "intent.toggle-recording.title"
|
||||||
|
/// The localized description of the intent, resolved from the widget target's string catalog.
|
||||||
|
static let description = IntentDescription("intent.toggle-recording.description")
|
||||||
|
/// Whether running the intent brings the app to the foreground; kept `false` so the button acts straight from the Live Activity,
|
||||||
|
/// in the app's background process, without opening the app.
|
||||||
static let openAppWhenRun = false
|
static let openAppWhenRun = false
|
||||||
|
|
||||||
// MARK: Methods
|
// MARK: Methods
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ private extension ActionButtonStyle {
|
|||||||
var backgroundColor: Color {
|
var backgroundColor: Color {
|
||||||
switch action {
|
switch action {
|
||||||
case .confirmative: .green
|
case .confirmative: .green
|
||||||
case let .custom(color): color
|
case .custom(let color): color
|
||||||
case .default: .yellow
|
case .default: .yellow
|
||||||
case .destructive: .red
|
case .destructive: .red
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,41 @@ struct RecordingControls: View {
|
|||||||
) {
|
) {
|
||||||
switch state.state {
|
switch state.state {
|
||||||
case .recording:
|
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()) {
|
Button(intent: ToggleRecordingIntent()) {
|
||||||
Image.Symbol.pause
|
Image.Symbol.pause
|
||||||
.resizable()
|
.resizable()
|
||||||
@@ -29,24 +64,11 @@ struct RecordingControls: View {
|
|||||||
.buttonStyle(.action(
|
.buttonStyle(.action(
|
||||||
type: .default
|
type: .default
|
||||||
))
|
))
|
||||||
|
.accessibilityLabel(Text("view.recording-controls.button.pause"))
|
||||||
case .paused:
|
|
||||||
Button(intent: DiscardRecordingIntent()) {
|
|
||||||
Image.Symbol.discard
|
|
||||||
.resizable()
|
|
||||||
}
|
}
|
||||||
.buttonStyle(.action(
|
|
||||||
type: .destructive
|
|
||||||
))
|
|
||||||
|
|
||||||
Button(intent: ToggleRecordingIntent()) {
|
|
||||||
Image.Symbol.microphone
|
|
||||||
.resizable()
|
|
||||||
}
|
|
||||||
.buttonStyle(.action(
|
|
||||||
type: .default
|
|
||||||
))
|
|
||||||
|
|
||||||
|
/// The send button, shown while the recording is paused, that sends it for processing.
|
||||||
|
var processButton: some View {
|
||||||
Button(intent: ProcessRecordingIntent()) {
|
Button(intent: ProcessRecordingIntent()) {
|
||||||
Image.Symbol.send
|
Image.Symbol.send
|
||||||
.resizable()
|
.resizable()
|
||||||
@@ -54,18 +76,19 @@ struct RecordingControls: View {
|
|||||||
.buttonStyle(.action(
|
.buttonStyle(.action(
|
||||||
type: .confirmative
|
type: .confirmative
|
||||||
))
|
))
|
||||||
|
.accessibilityLabel(Text("view.recording-controls.button.send"))
|
||||||
|
}
|
||||||
|
|
||||||
case .processing:
|
/// The resume button, shown while the recording is paused, that resumes it.
|
||||||
Button(intent: DiscardRecordingIntent()) {
|
var recordButton: some View {
|
||||||
Image.Symbol.discard
|
Button(intent: ToggleRecordingIntent()) {
|
||||||
|
Image.Symbol.microphone
|
||||||
.resizable()
|
.resizable()
|
||||||
}
|
}
|
||||||
.buttonStyle(.action(
|
.buttonStyle(.action(
|
||||||
type: .destructive
|
type: .default
|
||||||
))
|
))
|
||||||
}
|
.accessibilityLabel(Text("view.recording-controls.button.resume"))
|
||||||
}
|
|
||||||
.buttonStyle(.borderedProminent)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,17 +24,8 @@ struct RecordingStateLabel: View {
|
|||||||
Text(.viewRecordingStateLabelStateProcessing)
|
Text(.viewRecordingStateLabelStateProcessing)
|
||||||
}
|
}
|
||||||
} icon: {
|
} icon: {
|
||||||
switch state.state {
|
state.state.symbol
|
||||||
case .recording:
|
.foregroundStyle(state.state.tint)
|
||||||
Image.Symbol.microphone
|
|
||||||
.foregroundStyle(.yellow)
|
|
||||||
case .paused:
|
|
||||||
Image.Symbol.pause
|
|
||||||
.foregroundStyle(.yellow)
|
|
||||||
case .processing:
|
|
||||||
Image.Symbol.send
|
|
||||||
.foregroundStyle(.green)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.font(.body)
|
.font(.body)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import ActivityKit
|
import ActivityKit
|
||||||
import Commanding
|
|
||||||
import AppIntents
|
import AppIntents
|
||||||
|
import Commanding
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
import WidgetKit
|
import WidgetKit
|
||||||
|
|
||||||
@@ -37,36 +37,38 @@ struct RecordingLiveActivity: Widget {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
} compactLeading: {
|
} compactLeading: {
|
||||||
switch context.state.state {
|
image(
|
||||||
case .paused:
|
for: context.state.state
|
||||||
Image.Symbol.pause
|
)
|
||||||
.foregroundStyle(.yellow)
|
|
||||||
case .processing:
|
|
||||||
Image.Symbol.send
|
|
||||||
.foregroundStyle(.green)
|
|
||||||
case .recording:
|
|
||||||
Image.Symbol.microphone
|
|
||||||
.foregroundStyle(.yellow)
|
|
||||||
}
|
|
||||||
} compactTrailing: {
|
} compactTrailing: {
|
||||||
RecordingTimerText(
|
RecordingTimerText(
|
||||||
state: context.state
|
state: context.state
|
||||||
)
|
)
|
||||||
.frame(maxWidth: Constant.Size.compactTimer)
|
.frame(
|
||||||
|
maxWidth: Constant.Size.compactTimer
|
||||||
|
)
|
||||||
} minimal: {
|
} minimal: {
|
||||||
switch context.state.state {
|
image(
|
||||||
case .paused:
|
for: context.state.state
|
||||||
Image.Symbol.pause
|
)
|
||||||
.foregroundStyle(.yellow)
|
|
||||||
case .processing:
|
|
||||||
Image.Symbol.send
|
|
||||||
.foregroundStyle(.green)
|
|
||||||
case .recording:
|
|
||||||
Image.Symbol.microphone
|
|
||||||
.foregroundStyle(.yellow)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Helpers
|
||||||
|
|
||||||
|
private extension RecordingLiveActivity {
|
||||||
|
|
||||||
|
// MARK: Methods
|
||||||
|
|
||||||
|
/// The state's symbol, tinted to match, shown in the compact and minimal presentations of the Dynamic Island.
|
||||||
|
func image(
|
||||||
|
for state: RecordingActivityState
|
||||||
|
) -> some View {
|
||||||
|
state.symbol
|
||||||
|
.foregroundStyle(state.tint)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -80,28 +82,4 @@ private enum Constant {
|
|||||||
/// The maximum width of the timer in the compact trailing presentation of the Dynamic Island.
|
/// The maximum width of the timer in the compact trailing presentation of the Dynamic Island.
|
||||||
static let compactTimer: CGFloat = 44
|
static let compactTimer: CGFloat = 44
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The spacing constants.
|
|
||||||
enum Spacing {
|
|
||||||
/// The spacing between the elements of a stack.
|
|
||||||
static let stack: CGFloat = 8
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The system symbol constants.
|
|
||||||
enum Symbol {
|
|
||||||
/// The symbol of the discard button.
|
|
||||||
static let discard = "trash"
|
|
||||||
/// The symbol marking the recording flow.
|
|
||||||
static let microphone = "mic.fill"
|
|
||||||
/// The symbol of the main button while recording.
|
|
||||||
static let pause = "pause.fill"
|
|
||||||
/// The symbol of the main button while paused.
|
|
||||||
static let record = "record.circle"
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The time constants.
|
|
||||||
enum Time {
|
|
||||||
/// The span of the running timer, comfortably beyond the maximum lifetime of a Live Activity.
|
|
||||||
static let span: TimeInterval = 24 * 60 * 60
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user