- data backup
- I can't test it because I'm stuck on the login screen.
This commit is contained in:
92
refilc/ios/livecard/LiveActivityManager.swift
Normal file
92
refilc/ios/livecard/LiveActivityManager.swift
Normal file
@@ -0,0 +1,92 @@
|
||||
import ActivityKit
|
||||
import WidgetKit
|
||||
import Foundation
|
||||
|
||||
public struct LiveActivitiesAppAttributes: ActivityAttributes, Identifiable {
|
||||
public typealias LiveDeliveryData = ContentState
|
||||
public struct ContentState: Codable, Hashable {
|
||||
var color: String
|
||||
var icon: String
|
||||
var index: String
|
||||
var title: String
|
||||
var subtitle: String
|
||||
var description: String
|
||||
var startDate: Date
|
||||
var endDate: Date
|
||||
var date: ClosedRange<Date>
|
||||
var nextSubject: String
|
||||
var nextRoom: String
|
||||
}
|
||||
|
||||
public var id = UUID()
|
||||
}
|
||||
|
||||
@available(iOS 16.2, *)
|
||||
final class LiveActivityManager {
|
||||
static let shared = LiveActivityManager()
|
||||
var currentActivity: Activity<LiveActivitiesAppAttributes>?
|
||||
|
||||
class func create() {
|
||||
|
||||
Task {
|
||||
do {
|
||||
let contentState = LiveActivitiesAppAttributes.ContentState(color: globalLessonData.color, icon: globalLessonData.icon, index: globalLessonData.index, title: globalLessonData.title, subtitle: globalLessonData.subtitle, description: globalLessonData.description, startDate: globalLessonData.startDate, endDate: globalLessonData.endDate, date: globalLessonData.date, nextSubject: globalLessonData.nextSubject, nextRoom: globalLessonData.nextRoom)
|
||||
|
||||
let activityContent = ActivityContent(state: contentState, staleDate: globalLessonData.endDate, relevanceScore: 0)
|
||||
|
||||
let activity = try Activity<LiveActivitiesAppAttributes>.request(
|
||||
attributes: LiveActivitiesAppAttributes(),
|
||||
content: activityContent,
|
||||
pushType: nil
|
||||
)
|
||||
|
||||
activityID = activity.id
|
||||
print("Live Activity létrehozva. Azonosító: \(activity.id)")
|
||||
} catch {
|
||||
print("Hiba történt a Live Activity létrehozásakor: \(error)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class func update() {
|
||||
Task {
|
||||
for activity in Activity<LiveActivitiesAppAttributes>.activities {
|
||||
do {
|
||||
let contentState = LiveActivitiesAppAttributes.ContentState(color: globalLessonData.color, icon: globalLessonData.icon, index: globalLessonData.index, title: globalLessonData.title, subtitle: globalLessonData.subtitle, description: globalLessonData.description, startDate: globalLessonData.startDate, endDate: globalLessonData.endDate, date: globalLessonData.date, nextSubject: globalLessonData.nextSubject, nextRoom: globalLessonData.nextRoom)
|
||||
|
||||
let activityContent = ActivityContent(state: contentState, staleDate: globalLessonData.endDate, relevanceScore: 0)
|
||||
|
||||
await activity.update(activityContent)
|
||||
activityID = activity.id
|
||||
print("Live Activity frissítve. Azonosító: \(activity.id)")
|
||||
} catch {
|
||||
print("Hiba történt a Live Activity frissítésekor: \(error)")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class func stop() {
|
||||
if (activityID != "") {
|
||||
Task {
|
||||
for activity in Activity<LiveActivitiesAppAttributes>.activities{
|
||||
let contentState = LiveActivitiesAppAttributes.ContentState(color: globalLessonData.color, icon: globalLessonData.icon, index: globalLessonData.index, title: globalLessonData.title, subtitle: globalLessonData.subtitle, description: globalLessonData.description, startDate: globalLessonData.startDate, endDate: globalLessonData.endDate, date: globalLessonData.date, nextSubject: globalLessonData.nextSubject, nextRoom: globalLessonData.nextRoom)
|
||||
|
||||
await activity.end(ActivityContent(state: contentState, staleDate: Date.distantFuture),dismissalPolicy: .immediate)
|
||||
}
|
||||
activityID = nil
|
||||
print("Live Activity sikeresen leállítva")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class func isRunning(_ activityID: String) -> Bool {
|
||||
for activity in Activity<LiveActivitiesAppAttributes>.activities {
|
||||
if activity.id == activityID {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
@@ -1,31 +1,40 @@
|
||||
import Foundation
|
||||
import ActivityKit
|
||||
|
||||
class LessonData {
|
||||
var color: String
|
||||
var icon: String
|
||||
var index: String
|
||||
var title: String
|
||||
var subtitle: String
|
||||
var description: String
|
||||
var startDate: Date
|
||||
var endDate: Date
|
||||
var date: ClosedRange<Date>
|
||||
var nextSubject: String
|
||||
var nextRoom: String
|
||||
|
||||
init?() {
|
||||
let sharedDefault = UserDefaults(suiteName: "group.refilc2.livecard")!
|
||||
|
||||
self.color = sharedDefault.string(forKey: "color")!
|
||||
self.icon = sharedDefault.string(forKey: "icon")!
|
||||
self.index = sharedDefault.string(forKey: "index")!
|
||||
self.title = sharedDefault.string(forKey: "title")!
|
||||
self.subtitle = sharedDefault.string(forKey: "subtitle")!
|
||||
self.description = sharedDefault.string(forKey: "description")!
|
||||
self.startDate = Date(timeIntervalSince1970: Double(sharedDefault.string(forKey: "startDate")!)! / 1000)
|
||||
self.endDate = Date(timeIntervalSince1970: Double(sharedDefault.string(forKey: "endDate")!)! / 1000)
|
||||
date = self.startDate...self.endDate
|
||||
self.nextSubject = sharedDefault.string(forKey: "nextSubject")!
|
||||
self.nextRoom = sharedDefault.string(forKey: "nextRoom")!
|
||||
}
|
||||
public struct LessonData {
|
||||
var color: String
|
||||
var icon: String
|
||||
var index: String
|
||||
var title: String
|
||||
var subtitle: String
|
||||
var description: String
|
||||
var startDate: Date
|
||||
var endDate: Date
|
||||
var date: ClosedRange<Date>
|
||||
var nextSubject: String
|
||||
var nextRoom: String
|
||||
|
||||
init(from dictionary: [String: Any]) {
|
||||
self.color = dictionary["color"] as? String ?? ""
|
||||
self.icon = dictionary["icon"] as? String ?? ""
|
||||
self.index = dictionary["index"] as? String ?? ""
|
||||
self.title = dictionary["title"] as? String ?? ""
|
||||
self.subtitle = dictionary["subtitle"] as? String ?? ""
|
||||
self.description = dictionary["description"] as? String ?? ""
|
||||
self.nextSubject = dictionary["nextSubject"] as? String ?? ""
|
||||
self.nextRoom = dictionary["nextRoom"] as? String ?? ""
|
||||
|
||||
if let startDateStr = dictionary["startDate"] as? String, let startDateInt = Int(startDateStr) {
|
||||
self.startDate = Date(timeIntervalSince1970: TimeInterval(startDateInt) / 1000)
|
||||
} else {
|
||||
self.startDate = Date()
|
||||
}
|
||||
|
||||
if let endDateStr = dictionary["endDate"] as? String, let endDateInt = Int(endDateStr) {
|
||||
self.endDate = Date(timeIntervalSince1970: TimeInterval(endDateInt) / 1000)
|
||||
} else {
|
||||
self.endDate = Date()
|
||||
}
|
||||
date = self.startDate...self.endDate
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,8 +5,8 @@ import SwiftUI
|
||||
@main
|
||||
struct Widgets: WidgetBundle {
|
||||
var body: some Widget {
|
||||
if #available(iOS 16.1, *) {
|
||||
LiveCardWidget()
|
||||
if #available(iOS 16.2, *) {
|
||||
LiveCardWidget()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -37,22 +37,11 @@ extension Color {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// We need to redefined live activities pipe
|
||||
struct LiveActivitiesAppAttributes: ActivityAttributes, Identifiable {
|
||||
public struct ContentState: Codable, Hashable { }
|
||||
|
||||
var id = UUID()
|
||||
}
|
||||
|
||||
struct LockScreenLiveActivityView: View {
|
||||
let context: ActivityViewContext<LiveActivitiesAppAttributes>
|
||||
|
||||
let lesson = LessonData()
|
||||
|
||||
var body: some View {
|
||||
HStack(alignment: .center) {
|
||||
Image(systemName: lesson!.icon)
|
||||
Image(systemName: context.state.icon)
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(width: CGFloat(30), height: CGFloat(30))
|
||||
@@ -60,17 +49,17 @@ struct LockScreenLiveActivityView: View {
|
||||
|
||||
VStack(alignment: .leading) {
|
||||
HStack(alignment: .center) {
|
||||
Text(lesson!.index + lesson!.title)
|
||||
Text(context.state.index + context.state.title)
|
||||
.font(.title3)
|
||||
.bold()
|
||||
|
||||
Text(lesson!.subtitle)
|
||||
Text(context.state.subtitle)
|
||||
.font(.subheadline)
|
||||
.padding(.trailing, 12)
|
||||
}
|
||||
|
||||
if (lesson!.description != "") {
|
||||
Text(lesson!.description)
|
||||
if (context.state.description != "") {
|
||||
Text(context.state.description)
|
||||
.font(.subheadline)
|
||||
}
|
||||
|
||||
@@ -79,16 +68,16 @@ struct LockScreenLiveActivityView: View {
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(width: CGFloat(8), height: CGFloat(8))
|
||||
Text(lesson!.nextSubject)
|
||||
Text(context.state.nextSubject)
|
||||
.font(.caption)
|
||||
Text(lesson!.nextRoom)
|
||||
Text(context.state.nextRoom)
|
||||
.font(.caption2)
|
||||
}
|
||||
}.padding(15)
|
||||
|
||||
Spacer()
|
||||
|
||||
Text(timerInterval: lesson!.date, countsDown: true)
|
||||
Text(timerInterval: context.state.date, countsDown: true)
|
||||
.multilineTextAlignment(.center)
|
||||
.frame(width: 85)
|
||||
.font(.title2)
|
||||
@@ -96,110 +85,105 @@ struct LockScreenLiveActivityView: View {
|
||||
.padding(.trailing, CGFloat(24))
|
||||
}
|
||||
.activityBackgroundTint(
|
||||
lesson!.color != "#676767"
|
||||
? Color(hex: lesson!.color)
|
||||
context.state.color != "#676767"
|
||||
? Color(hex: context.state.color)
|
||||
// Ha nem megy hat nem megy
|
||||
: Color.clear
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOSApplicationExtension 16.1, *)
|
||||
@available(iOSApplicationExtension 16.2, *)
|
||||
struct LiveCardWidget: Widget {
|
||||
var body: some WidgetConfiguration {
|
||||
/// Live Activity Notification
|
||||
ActivityConfiguration(for: LiveActivitiesAppAttributes.self) { context in
|
||||
LockScreenLiveActivityView(context: context)
|
||||
/// Dynamic Island
|
||||
} dynamicIsland: { context in
|
||||
let lesson = LessonData()
|
||||
|
||||
/// Expanded
|
||||
return DynamicIsland {
|
||||
DynamicIslandExpandedRegion(.leading) {
|
||||
VStack {
|
||||
Spacer()
|
||||
ProgressView(
|
||||
timerInterval: lesson!.date,
|
||||
countsDown: true,
|
||||
label: {
|
||||
Image(systemName: lesson!.icon)
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(width: CGFloat(32), height: CGFloat(32))
|
||||
},
|
||||
currentValueLabel: {
|
||||
Image(systemName: lesson!.icon)
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(width: CGFloat(32), height: CGFloat(32))
|
||||
}
|
||||
).progressViewStyle(.circular)
|
||||
}
|
||||
}
|
||||
DynamicIslandExpandedRegion(.center) {
|
||||
VStack(alignment: .leading) {
|
||||
Text(lesson!.index + lesson!.title)
|
||||
.lineLimit(1)
|
||||
.font(.title3)
|
||||
.bold()
|
||||
|
||||
Text(lesson!.description)
|
||||
.lineLimit(2)
|
||||
.font(.caption)
|
||||
}.padding(EdgeInsets(top: 0.0, leading: 5.0, bottom: 0.0, trailing: 0.0))
|
||||
}
|
||||
DynamicIslandExpandedRegion(.trailing) {
|
||||
VStack {
|
||||
Spacer()
|
||||
Text(lesson!.subtitle)
|
||||
.lineLimit(1)
|
||||
.font(.subheadline)
|
||||
Spacer()
|
||||
}
|
||||
}
|
||||
|
||||
/// Compact
|
||||
} compactLeading: {
|
||||
Label {
|
||||
Text(lesson!.title)
|
||||
} icon: {
|
||||
Image(systemName: lesson!.icon)
|
||||
}
|
||||
.font(.caption2)
|
||||
}
|
||||
compactTrailing: {
|
||||
Text(timerInterval: lesson!.date, countsDown: true)
|
||||
.multilineTextAlignment(.center)
|
||||
.frame(width: 40)
|
||||
.font(.caption2)
|
||||
|
||||
/// Collapsed
|
||||
} minimal: {
|
||||
VStack(alignment: .center, content: {
|
||||
ProgressView(
|
||||
timerInterval: lesson!.date,
|
||||
countsDown: true,
|
||||
label: {
|
||||
Image(systemName: lesson!.icon)
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(width: CGFloat(12), height: CGFloat(12))
|
||||
},
|
||||
currentValueLabel: {
|
||||
Image(systemName: lesson!.icon)
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(width: CGFloat(12), height: CGFloat(12))
|
||||
var body: some WidgetConfiguration {
|
||||
/// Live Activity Notification
|
||||
ActivityConfiguration(for: LiveActivitiesAppAttributes.self) { context in
|
||||
LockScreenLiveActivityView(context: context)
|
||||
/// Dynamic Island
|
||||
} dynamicIsland: { context in
|
||||
|
||||
/// Expanded
|
||||
return DynamicIsland {
|
||||
DynamicIslandExpandedRegion(.leading) {
|
||||
VStack {
|
||||
Spacer()
|
||||
ProgressView(
|
||||
timerInterval: context.state.date,
|
||||
countsDown: true,
|
||||
label: {
|
||||
Image(systemName: context.state.icon)
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(width: CGFloat(32), height: CGFloat(32))
|
||||
},
|
||||
currentValueLabel: {
|
||||
Image(systemName: context.state.icon)
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(width: CGFloat(32), height: CGFloat(32))
|
||||
}
|
||||
).progressViewStyle(.circular)
|
||||
}
|
||||
}
|
||||
DynamicIslandExpandedRegion(.center) {
|
||||
VStack(alignment: .center) {
|
||||
Text(context.state.index + context.state.title)
|
||||
.lineLimit(1)
|
||||
.font(.body)
|
||||
.bold()
|
||||
|
||||
Text(context.state.subtitle)
|
||||
.lineLimit(1)
|
||||
.font(.subheadline)
|
||||
Spacer()
|
||||
|
||||
Text(context.state.description)
|
||||
.lineLimit(2)
|
||||
.font(.caption)
|
||||
}.padding(EdgeInsets(top: 0.0, leading: 5.0, bottom: 0.0, trailing: 0.0))
|
||||
}
|
||||
|
||||
/// Compact
|
||||
} compactLeading: {
|
||||
Label {
|
||||
Text(context.state.title)
|
||||
} icon: {
|
||||
Image(systemName: context.state.icon)
|
||||
}
|
||||
.font(.caption2)
|
||||
}
|
||||
).progressViewStyle(.circular)
|
||||
})
|
||||
}
|
||||
.keylineTint(
|
||||
lesson!.color != "#676767"
|
||||
? Color(hex: lesson!.color)
|
||||
: Color.clear
|
||||
)
|
||||
compactTrailing: {
|
||||
Text(timerInterval: context.state.date, countsDown: true)
|
||||
.multilineTextAlignment(.center)
|
||||
.frame(width: 40)
|
||||
.font(.caption2)
|
||||
|
||||
/// Collapsed
|
||||
} minimal: {
|
||||
VStack(alignment: .center, content: {
|
||||
ProgressView(
|
||||
timerInterval: context.state.date,
|
||||
countsDown: true,
|
||||
label: {
|
||||
Image(systemName: context.state.icon)
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(width: CGFloat(12), height: CGFloat(12))
|
||||
},
|
||||
currentValueLabel: {
|
||||
Image(systemName: context.state.icon)
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(width: CGFloat(12), height: CGFloat(12))
|
||||
}
|
||||
).progressViewStyle(.circular)
|
||||
})
|
||||
}
|
||||
.keylineTint(
|
||||
context.state.color != "#676767"
|
||||
? Color(hex: context.state.color)
|
||||
: Color.clear
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user