You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
HMG_Patient_App_New/ios/liveapp/liveappLiveActivity.swift

333 lines
12 KiB
Swift

//
// liveappLiveActivity.swift
// liveapp
//
// Created by Cloud Solutions on 14/12/2025.
//
import ActivityKit
import WidgetKit
import SwiftUI
struct LiveActivitiesAppAttributes: ActivityAttributes, Identifiable {
public typealias LiveDeliveryData = ContentState
public struct ContentState: Codable, Hashable { }
var id = UUID()
}
// Create shared default with custom group
let sharedDefault = UserDefaults(suiteName: "group.alhabib.patientApp")!
@available(iOSApplicationExtension 16.1, *)
struct FootballMatchApp: Widget {
var body: some WidgetConfiguration {
ActivityConfiguration(for: LiveActivitiesAppAttributes.self) { context in
let matchName = sharedDefault.string(forKey: context.attributes.prefixedKey("matchName"))!
let ruleFile = sharedDefault.string(forKey: context.attributes.prefixedKey("ruleFile"))!
let teamAName = sharedDefault.string(forKey: context.attributes.prefixedKey("teamAName"))!
let teamAState = sharedDefault.string(forKey: context.attributes.prefixedKey("teamAState"))!
let teamAScore = sharedDefault.integer(forKey: context.attributes.prefixedKey("teamAScore"))
let teamALogo = sharedDefault.string(forKey: context.attributes.prefixedKey("teamALogo"))!
let teamBName = sharedDefault.string(forKey: context.attributes.prefixedKey("teamBName"))!
let teamBState = sharedDefault.string(forKey: context.attributes.prefixedKey("teamBState"))!
let teamBScore = sharedDefault.integer(forKey: context.attributes.prefixedKey("teamBScore"))
let teamBLogo = sharedDefault.string(forKey: context.attributes.prefixedKey("teamBLogo"))!
let rule = (try? String(contentsOfFile: ruleFile, encoding: .utf8)) ?? ""
let matchStartDate = Date(timeIntervalSince1970: sharedDefault.double(forKey: context.attributes.prefixedKey("matchStartDate")) / 1000)
let matchEndDate = Date(timeIntervalSince1970: sharedDefault.double(forKey: context.attributes.prefixedKey("matchEndDate")) / 1000)
let matchRemainingTime = matchStartDate...matchEndDate
ZStack {
LinearGradient(colors: [Color.black.opacity(0.5),Color.black.opacity(0.3)], startPoint: .topLeading, endPoint: .bottom)
HStack {
ZStack {
VStack(alignment: .center, spacing: 2.0) {
Spacer()
Text(teamAName)
.lineLimit(1)
.font(.subheadline)
.fontWeight(.bold)
.multilineTextAlignment(.center)
Text(teamAState)
.lineLimit(1)
.font(.footnote)
.fontWeight(.bold)
.multilineTextAlignment(.center)
}
.frame(width: 70, height: 120)
.padding(.bottom, 8)
.padding(.top, 8)
.background(.white.opacity(0.4), in: RoundedRectangle(cornerRadius: 16, style: .continuous))
ZStack {
if let uiImageTeamA = UIImage(contentsOfFile: teamALogo)
{
Image(uiImage: uiImageTeamA)
.resizable()
.frame(width: 80, height: 80)
.offset(y:-20)
}
}
}
VStack(alignment: .center, spacing: 6.0) {
HStack {
Text("\(teamAScore)")
.font(.title)
.fontWeight(.bold)
Text(":")
.font(.title)
.fontWeight(.bold)
.foregroundStyle(.primary)
Text("\(teamBScore)")
.font(.title)
.fontWeight(.bold)
}
.padding(.horizontal, 5.0)
.background(.white.opacity(0.4), in: RoundedRectangle(cornerRadius: 8, style: .continuous))
HStack(alignment: .center, spacing: 2.0) {
Text(timerInterval: matchRemainingTime, countsDown: true)
.multilineTextAlignment(.center)
.frame(width: 50)
.monospacedDigit()
.font(.footnote)
.foregroundStyle(.white)
}
VStack(alignment: .center, spacing: 1.0) {
Link(destination: URL(string: "la://my.app/stats")!) {
Text("See stats 📊")
}.padding(.vertical, 5).padding(.horizontal, 5)
Text(matchName)
.font(.footnote)
.foregroundStyle(.white)
.padding(.bottom, 5)
Text(rule)
.font(.footnote)
.foregroundStyle(.white.opacity(0.5))
}
}
.padding(.vertical, 6.0)
ZStack {
VStack(alignment: .center, spacing: 2.0) {
Spacer()
Text(teamBName)
.lineLimit(1)
.font(.subheadline)
.fontWeight(.bold)
.multilineTextAlignment(.center)
Text(teamBState)
.lineLimit(1)
.font(.footnote)
.fontWeight(.bold)
.multilineTextAlignment(.center)
}
.frame(width: 70, height: 120)
.padding(.bottom, 8)
.padding(.top, 8)
.background(.white.opacity(0.4), in: RoundedRectangle(cornerRadius: 16, style: .continuous))
ZStack {
if let uiImageTeamB = UIImage(contentsOfFile: teamBLogo)
{
Image(uiImage: uiImageTeamB)
.resizable()
.frame(width: 80, height: 80)
.offset(y:-20)
}
}
}
}
.padding(.horizontal, 2.0)
}.frame(height: 160)
} dynamicIsland: { context in
let matchName = sharedDefault.string(forKey: context.attributes.prefixedKey("matchName"))!
let teamAName = sharedDefault.string(forKey: context.attributes.prefixedKey("teamAName"))!
let teamAState = sharedDefault.string(forKey: context.attributes.prefixedKey("teamAState"))!
let teamAScore = sharedDefault.integer(forKey: context.attributes.prefixedKey("teamAScore"))
let teamALogo = sharedDefault.string(forKey: context.attributes.prefixedKey("teamALogo"))!
let teamBName = sharedDefault.string(forKey: context.attributes.prefixedKey("teamBName"))!
let teamBState = sharedDefault.string(forKey: context.attributes.prefixedKey("teamBState"))!
let teamBScore = sharedDefault.integer(forKey: context.attributes.prefixedKey("teamBScore"))
let teamBLogo = sharedDefault.string(forKey: context.attributes.prefixedKey("teamBLogo"))!
let matchStartDate = Date(timeIntervalSince1970: sharedDefault.double(forKey: context.attributes.prefixedKey("matchStartDate")) / 1000)
let matchEndDate = Date(timeIntervalSince1970: sharedDefault.double(forKey: context.attributes.prefixedKey("matchEndDate")) / 1000)
let matchRemainingTime = matchStartDate...matchEndDate
return DynamicIsland {
DynamicIslandExpandedRegion(.leading) {
VStack(alignment: .center, spacing: 2.0) {
if let uiImageTeamA = UIImage(contentsOfFile: teamALogo)
{
Image(uiImage: uiImageTeamA)
.resizable()
.frame(width: 80, height: 80)
.offset(y:0)
}
Spacer()
Text(teamAName)
.lineLimit(1)
.font(.subheadline)
.fontWeight(.bold)
.multilineTextAlignment(.center)
Text(teamAState)
.lineLimit(1)
.font(.footnote)
.fontWeight(.bold)
.multilineTextAlignment(.center)
}
.frame(width: 70, height: 120)
.padding(.bottom, 8)
.padding(.top, 8)
}
DynamicIslandExpandedRegion(.trailing) {
VStack(alignment: .center, spacing: 2.0) {
if let uiImageTeamB = UIImage(contentsOfFile: teamBLogo)
{
Image(uiImage: uiImageTeamB)
.resizable()
.frame(width: 80, height: 80)
.offset(y:0)
}
Spacer()
Text(teamBName)
.lineLimit(1)
.font(.subheadline)
.fontWeight(.bold)
.multilineTextAlignment(.center)
Text(teamBState)
.lineLimit(1)
.font(.footnote)
.fontWeight(.bold)
.multilineTextAlignment(.center)
}
.frame(width: 70, height: 120)
.padding(.bottom, 8)
.padding(.top, 8)
}
DynamicIslandExpandedRegion(.center) {
VStack(alignment: .center, spacing: 6.0) {
HStack {
Text("\(teamAScore)")
.font(.title)
.fontWeight(.bold)
Text(":")
.font(.title)
.fontWeight(.bold)
.foregroundStyle(.primary)
Text("\(teamBScore)")
.font(.title)
.fontWeight(.bold)
}
.padding(.horizontal, 5.0)
.background(.thinMaterial, in: RoundedRectangle(cornerRadius: 8, style: .continuous))
HStack(alignment: .center, spacing: 2.0) {
Text(timerInterval: matchRemainingTime, countsDown: true)
.multilineTextAlignment(.center)
.frame(width: 50)
.monospacedDigit()
.font(.footnote)
.foregroundStyle(.white)
}
VStack(alignment: .center, spacing: 1.0) {
Link(destination: URL(string: "la://my.app/stats")!) {
Text("See stats 📊")
}.padding(.vertical, 5).padding(.horizontal, 5)
Text(matchName)
.font(.footnote)
.foregroundStyle(.white)
}
}
.padding(.vertical, 6.0)
}
} compactLeading: {
HStack {
if let uiImageTeamA = UIImage(contentsOfFile: teamALogo)
{
Image(uiImage: uiImageTeamA)
.resizable()
.frame(width: 26, height: 26)
}
Text("\(teamAScore)")
.font(.title)
.fontWeight(.bold)
}
} compactTrailing: {
HStack {
Text("\(teamBScore)")
.font(.title)
.fontWeight(.bold)
if let uiImageTeamB = UIImage(contentsOfFile: teamBLogo)
{
Image(uiImage: uiImageTeamB)
.resizable()
.frame(width: 26, height: 26)
}
}
} minimal: {
ZStack {
if let uiImageTeamA = UIImage(contentsOfFile: teamALogo)
{
Image(uiImage: uiImageTeamA)
.resizable()
.frame(width: 26, height: 26)
.offset(x:-6)
}
if let uiImageTeamB = UIImage(contentsOfFile: teamBLogo)
{
Image(uiImage: uiImageTeamB)
.resizable()
.frame(width: 26, height: 26)
.offset(x:6)
}
}
}
}
}
}
extension LiveActivitiesAppAttributes {
func prefixedKey(_ key: String) -> String {
return "\(id)_\(key)"
}
}