RecordingLiveActivityManager.swift 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. import ActivityKit
  2. import Foundation
  3. @MainActor
  4. final class RecordingLiveActivityManager {
  5. static let shared = RecordingLiveActivityManager()
  6. private var activity: Activity<RecordingActivityAttributes>?
  7. private init() {}
  8. var recoverableSessionID: UUID? {
  9. activity?.attributes.sessionID
  10. ?? Activity<RecordingActivityAttributes>.activities.first?.attributes.sessionID
  11. }
  12. func start(
  13. sessionID: UUID,
  14. title: String,
  15. sourceName: String,
  16. elapsedSeconds: TimeInterval
  17. ) {
  18. guard ActivityAuthorizationInfo().areActivitiesEnabled else { return }
  19. Task {
  20. await endExistingActivities()
  21. let attributes = RecordingActivityAttributes(
  22. sessionID: sessionID,
  23. title: title,
  24. sourceName: sourceName
  25. )
  26. let state = makeState(elapsedSeconds: elapsedSeconds, isPaused: false)
  27. do {
  28. activity = try Activity.request(
  29. attributes: attributes,
  30. content: ActivityContent(state: state, staleDate: nil),
  31. pushType: nil
  32. )
  33. } catch {
  34. print("[RecordingLiveActivity] Failed to start: \(error.localizedDescription)")
  35. }
  36. }
  37. }
  38. func update(elapsedSeconds: TimeInterval, isPaused: Bool) {
  39. guard let activity else { return }
  40. let state = makeState(elapsedSeconds: elapsedSeconds, isPaused: isPaused)
  41. Task {
  42. await activity.update(ActivityContent(state: state, staleDate: nil))
  43. }
  44. }
  45. func end(elapsedSeconds: TimeInterval) {
  46. guard let activity else { return }
  47. self.activity = nil
  48. let finalState = makeState(elapsedSeconds: elapsedSeconds, isPaused: true)
  49. Task {
  50. await activity.end(
  51. ActivityContent(state: finalState, staleDate: nil),
  52. dismissalPolicy: .immediate
  53. )
  54. }
  55. }
  56. private func endExistingActivities() async {
  57. for existingActivity in Activity<RecordingActivityAttributes>.activities {
  58. await existingActivity.end(nil, dismissalPolicy: .immediate)
  59. }
  60. }
  61. private func makeState(
  62. elapsedSeconds: TimeInterval,
  63. isPaused: Bool
  64. ) -> RecordingActivityAttributes.ContentState {
  65. RecordingActivityAttributes.ContentState(
  66. timerStartDate: Date().addingTimeInterval(-elapsedSeconds),
  67. elapsedSeconds: elapsedSeconds,
  68. isPaused: isPaused
  69. )
  70. }
  71. }