Skip to content

Instantly share code, notes, and snippets.

@mergesort
Created December 8, 2022 22:15
Show Gist options
  • Save mergesort/cf57ddc44e7b469973e889a11b2d26a9 to your computer and use it in GitHub Desktop.
Save mergesort/cf57ddc44e7b469973e889a11b2d26a9 to your computer and use it in GitHub Desktop.
public final class LiveActivitiesController<Model: Identifiable & Equatable & Codable, ModelActivity: ActivityAttributes & Identifiable>: ObservableObject {
var activityFromModel: (Model) -> ModelActivity
var contentStateFromModel: (Model) -> ModelActivity.ContentState
public init(activityFromModel: @escaping (Model) -> ModelActivity, contentStateFromModel: @escaping (Model) -> ModelActivity.ContentState) {
self.activityFromModel = activityFromModel
self.contentStateFromModel = contentStateFromModel
}
public func activityIsActive(_ model: Model) -> Bool {
return self.allActivities.map(\.attributes.id).contains(where: { $0 == self.activityFromModel(model).id })
}
public func startActivity(_ model: Model) async throws {
do {
_ = try Activity.request(
attributes: self.activityFromModel(model),
contentState: self.contentStateFromModel(model)
)
} catch {
print(error)
}
}
public func updateActivity(_ reminder: Model) async {
let state = contentStateFromModel(reminder)
await self.activityMatching(reminder)?.update(using: state)
}
public func endActivity(_ reminder: Model) async {
await self.activityMatching(reminder)?.end(dismissalPolicy: .immediate)
}
}
private extension LiveActivitiesController {
var allActivities: [Activity<ModelActivity>] {
return Activity<ModelActivity>.activities
}
func activityMatching(_ model: Model) async -> Activity<ModelActivity>? {
self.allActivities.first(where: { $0.attributes.id == self.activityFromModel(model).id })
}
}
// Create a Reminder Model
public struct Reminder: Identifiable, Equatable, Codable {
public let id: UUID
public var createdAt: Date
public var updatedAt: Date
public var creator: String
public var title: String
public var hexColor: String
public var description: String
public var isArchived: Bool
}
// Create a Reminder live acitivy model
public struct ReminderActivity: ActivityAttributes, Identifiable {
// Static properties for your activity that cannot change after initialization
public var id: UUID
public init(id: UUID) {
self.id = id
}
public struct ContentState: Codable, Hashable {
// Dynamic (state changing) properties about your activity, cannot be more than 4kb per property
public var title: String
public var description: String
public var hexColor: String
public init(title: String, description: String, hexColor: String) {
self.title = title
self.description = description
self.hexColor = hexColor
}
}
}
// The view for your live activity
struct ReminderLockScreenLiveActivityView: View {
let context: ActivityViewContext<ReminderActivity>
var body: some View {
VStack(alignment: .leading, spacing: 4.0) {
Text(context.state.title)
.lineLimit(3)
.bold()
.font(.title2)
Text(context.state.description)
.font(.title3)
Spacer()
}
.multilineTextAlignment(.leading)
.padding(16.0)
.frame(maxWidth: .infinity, alignment: .leading)
.background(Color(hex: context.state.hexColor))
.foregroundColor(Color.white)
}
}
@StateObject private var liveActivitiesController = LiveActivitiesController<Reminder, ReminderActivity>(
activityFromModel: { reminder in
ReminderActivity(id: reminder.id)
},
contentStateFromModel: { reminder in
ReminderActivity.ContentState(title: reminder.title, description: reminder.description ?? "", hexColor: reminder.hexColor)
}
)
// Check a live activity is active
if self.liveActivitiesController.activityIsActive(reminder) {
// End a live activity
await liveActivitiesController.endActivity(reminder)
} else {
// Start a new live activity
try await liveActivitiesController.startActivity(reminder)
}
// Update a live activity with new data
await liveActivitiesController.updateActivity(reminder)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment