import ActivityKit import WidgetKit import SwiftUI struct LiveActivitiesAppAttributes: ActivityAttributes, Identifiable { public typealias LiveDeliveryData = ContentState // don't forget to add this line, otherwise, live activity will not display it. public struct ContentState: Codable, Hashable { } var id = UUID() } let sharedDefault = UserDefaults(suiteName: "group.alhabib.patientApp")! struct AppWidgetAttributes: ActivityAttributes { public struct ContentState: Codable, Hashable { // Dynamic stateful properties about your activity go here! var emoji: String } // Fixed non-changing properties about your activity go here! var name: String } extension Color { static let redColorText = Color(hex: "#ED1C2B") static let yellowColor = Color(hex: "#FFAF15") static let successColor = Color(hex: "#18C273") static let inactiveColor = Color(hex: "#ED1C2B") static let textColor = Color(hex: "#A2A2A2") static let colorWhite = Color(hex: "#FFFFFF") // Helper initializer for hex colors init(hex: String) { let hex = hex.trimmingCharacters(in: CharacterSet.alphanumerics.inverted) var int: UInt64 = 0 Scanner(string: hex).scanHexInt64(&int) let a, r, g, b: UInt64 switch hex.count { case 3: // RGB (12-bit) (a, r, g, b) = (255, (int >> 8) * 17, (int >> 4 & 0xF) * 17, (int & 0xF) * 17) case 6: // RGB (24-bit) (a, r, g, b) = (255, int >> 16, int >> 8 & 0xFF, int & 0xFF) case 8: // ARGB (32-bit) (a, r, g, b) = (int >> 24, int >> 16 & 0xFF, int >> 8 & 0xFF, int & 0xFF) default: (a, r, g, b) = (255, 0, 0, 0) } self.init( .sRGB, red: Double(r) / 255, green: Double(g) / 255, blue: Double(b) / 255, opacity: Double(a) / 255 ) } } // MARK: - Widget Configuration based on nextStepBackground struct WidgetColorConfig { let nextStepBackground: Color let nextStepTextColor: Color let containerBorderColor: Color static func config(for value: Int) -> WidgetColorConfig { switch value { case 0: return WidgetColorConfig( nextStepBackground: .inactiveColor, nextStepTextColor: .textColor, containerBorderColor: .yellowColor ) case 1: return WidgetColorConfig( nextStepBackground: .redColorText, nextStepTextColor: .colorWhite, containerBorderColor: .redColorText ) case 2: return WidgetColorConfig( nextStepBackground: .successColor, nextStepTextColor: .colorWhite, containerBorderColor: .successColor ) default: return WidgetColorConfig( nextStepBackground: .inactiveColor, nextStepTextColor: .textColor, containerBorderColor: .yellowColor ) } } } // MARK: - Widget Data Model struct NotificationWidgetData { let currentTicket: String let currentlyServingHeader: String let currentlyServing: String let status: String let nextStep: String let imageName: String let colorConfig: WidgetColorConfig } struct NotificationWidgetView: View { private let data: NotificationWidgetData init(data: NotificationWidgetData) { print("it is being loaded") self.data = data } var body: some View { ZStack { data.colorConfig.containerBorderColor // Background color .edgesIgnoringSafeArea(.all) // Ensure it covers the entire screen VStack(alignment: .leading, spacing: 0) { // Top section with current ticket and image HStack(alignment: .top, spacing: 0) { // Current ticket value Text(data.currentTicket) .font(.custom("Poppins-Medium", size: 28)) .fontWeight(.bold) .foregroundColor(.black) .padding(.trailing, 10) .frame(maxWidth: .infinity, alignment: .leading) Image(data.imageName) .resizable() .scaledToFit() .frame(width: 34, height: 34) } .padding(.top, 16) .padding(.horizontal, 16) // Currently Serving Header Text(data.currentlyServingHeader) .font(.custom("Poppins-Medium", size: 14)) .fontWeight(.bold) .foregroundColor(.black) .padding(.trailing, 12) .padding(.bottom, 10) .padding(.horizontal, 16) // Currently Serving section with status HStack(alignment: .center, spacing: 0) { // Currently serving text Text(data.currentlyServing) .font(.custom("Poppins-Medium", size: 16)) .fontWeight(.bold) .foregroundColor(.black) .frame(maxWidth: .infinity, alignment: .leading) // Status badge Text(data.status) .font(.custom("Poppins-Medium", size: 12)) .foregroundColor(data.colorConfig.nextStepTextColor) .padding(.horizontal, 12) .padding(.vertical, 8) .background( RoundedRectangle(cornerRadius: 8) .fill(Color.inactiveColor.opacity(0.2)) ) } .padding(.horizontal, 16) Spacer() // Next Step badge Text(data.nextStep) .font(.custom("Poppins-Medium", size: 12)) .foregroundColor(data.colorConfig.nextStepTextColor) .padding(.horizontal, 12) .padding(.vertical, 8) .background( RoundedRectangle(cornerRadius: 8) .fill(data.colorConfig.nextStepBackground) ) .padding(.horizontal, 16) .padding(.bottom, 16) } .background(Color.white) // Ensure content has a white background .cornerRadius(20) .padding() // Add padding to ensure it doesn't touch the edges } } } // MARK: - Live Activity Widget struct AppWidgetLiveActivity: Widget { var body: some WidgetConfiguration { ActivityConfiguration(for: LiveActivitiesAppAttributes.self) { context in // Extract parameters from Flutter print("it is being loaded") // print("the queno is \(context.attributes.prefixedKey("title")) ===== \(sharedDefault.string(forKey: context.attributes.prefixedKey("queueNo")) )") let title = sharedDefault.string(forKey: context.attributes.prefixedKey("title")) ?? "testes" let contentText = sharedDefault.string(forKey: context.attributes.prefixedKey("contentText")) ?? "tested" let currentTicket = sharedDefault.string(forKey: context.attributes.prefixedKey("queueNo")) ?? "test1234" let status = sharedDefault.string(forKey: context.attributes.prefixedKey("callType")) ?? "test3345" let currentlyServing = sharedDefault.string(forKey: context.attributes.prefixedKey("currentlyServingTitle")) ?? "tes" let nextStep = sharedDefault.string(forKey: context.attributes.prefixedKey("currentlyServingStatus")) ?? "test111" let nextStepBackground = sharedDefault.integer(forKey: context.attributes.prefixedKey("currentlyServingCallType")) // Get color configuration based on nextStepBackground let colorConfig = WidgetColorConfig.config(for: nextStepBackground) // Create widget data let widgetData = NotificationWidgetData( currentTicket: currentTicket, currentlyServingHeader: "Currently Servingsssssssss:", currentlyServing: currentlyServing, status: status, nextStep: nextStep, imageName:"hmg", colorConfig: colorConfig ) NotificationWidgetView(data: widgetData) .activityBackgroundTint(Color.clear) .activitySystemActionForegroundColor(Color.black) } dynamicIsland: { context in let title = sharedDefault.string(forKey: context.attributes.prefixedKey("title")) ?? "testes" let contentText = sharedDefault.string(forKey: context.attributes.prefixedKey("contentText")) ?? "tested" let currentTicket = sharedDefault.string(forKey: context.attributes.prefixedKey("queueNo")) ?? "test1234" let status = sharedDefault.string(forKey: context.attributes.prefixedKey("callType")) ?? "test3345" let currentlyServing = sharedDefault.string(forKey: context.attributes.prefixedKey("currentlyServingTitle")) ?? "tes" let nextStep = sharedDefault.string(forKey: context.attributes.prefixedKey("currentlyServingStatus")) ?? "test111" let nextStepBackground = sharedDefault.integer(forKey: context.attributes.prefixedKey("currentlyServingCallType")) let colorConfig = WidgetColorConfig.config(for: nextStepBackground) return DynamicIsland { // Expanded UI DynamicIslandExpandedRegion(.leading) { VStack(alignment: .leading) { Text(currentTicket) .font(.system(size: 24, weight: .bold)) .foregroundColor(.primary) } } DynamicIslandExpandedRegion(.trailing) { Image("hmg") .resizable() .scaledToFit() .frame(width: 34, height: 34) .foregroundColor(.gray) } DynamicIslandExpandedRegion(.center) { VStack(spacing: 4) { Text("Currently Serving:") .font(.caption2) .foregroundColor(.secondary) Text(currentlyServing) .font(.caption) .fontWeight(.semibold) } } DynamicIslandExpandedRegion(.bottom) { HStack { Text(status) .font(.caption2) .padding(.horizontal, 8) .padding(.vertical, 4) .background( RoundedRectangle(cornerRadius: 6) .fill(colorConfig.nextStepBackground.opacity(0.2)) ) Spacer() Text(nextStep) .font(.caption2) .foregroundColor(colorConfig.nextStepTextColor) .padding(.horizontal, 8) .padding(.vertical, 4) .background( RoundedRectangle(cornerRadius: 6) .fill(colorConfig.nextStepBackground) ) } .padding(.horizontal) } } compactLeading: { // Compact leading view Text(currentTicket) .font(.caption2) .fontWeight(.bold) } compactTrailing: { // Compact trailing view Image("hmg") .resizable() .scaledToFit() .frame(width: 12, height: 12) .foregroundColor(colorConfig.containerBorderColor).padding(4) } minimal: { // Minimal view HStack{ Text(currentTicket) .font(.caption2) .fontWeight(.bold) Spacer() Image("hmg") .resizable() .scaledToFit() .frame(width: 4, height: 4) .foregroundColor(colorConfig.containerBorderColor) }.padding(2) } .contentMargins(.all, 20,for: .expanded) } } } extension LiveActivitiesAppAttributes { func prefixedKey(_ key: String) -> String { return "\(id)_\(key)" } } // MARK: - Preview for Testing struct NotificationWidgetView_Previews: PreviewProvider { static var previews: some View { Group { // Preview with nextStepBackground = 0 (Yellow border) NotificationWidgetView( data: NotificationWidgetData( currentTicket: "42", currentlyServingHeader: "Currently Serving3:", currentlyServing: "Customer #15", status: "Pending", nextStep: "Next: Prepare Order", imageName: "bell.fill", colorConfig: .config(for: 0) ) ) .previewDisplayName("Yellow Border (0)") // Preview with nextStepBackground = 1 (Red border) NotificationWidgetView( data: NotificationWidgetData( currentTicket: "89", currentlyServingHeader: "Currently Serving2:", currentlyServing: "Customer #67", status: "Active", nextStep: "Next: Quality Check", imageName: "bell.fill", colorConfig: .config(for: 1) ) ) .previewDisplayName("Red Border (1)") // Preview with nextStepBackground = 2 (Green border) NotificationWidgetView( data: NotificationWidgetData( currentTicket: "125", currentlyServingHeader: "Currently Serving1:", currentlyServing: "Customer #98", status: "Completed", nextStep: "Next: Ready for Pickup", imageName: "bell.fill", colorConfig: .config(for: 2) ) ) .previewDisplayName("Green Border (2)") } .padding() .previewLayout(.sizeThatFits) } }