LiveActivity.swift 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. import ActivityKit
  2. import Charts
  3. import SwiftUI
  4. import WidgetKit
  5. struct LiveActivity: Widget {
  6. let dateFormatter: DateFormatter = {
  7. var f = DateFormatter()
  8. f.dateStyle = .none
  9. f.timeStyle = .short
  10. return f
  11. }()
  12. func changeLabel(context: ActivityViewContext<LiveActivityAttributes>) -> Text {
  13. if !context.isStale && !context.state.change.isEmpty {
  14. Text(context.state.change)
  15. } else {
  16. Text("--")
  17. }
  18. }
  19. func updatedLabel(context: ActivityViewContext<LiveActivityAttributes>) -> Text {
  20. Text(dateFormatter.string(from: context.state.date))
  21. }
  22. func bgLabel(context: ActivityViewContext<LiveActivityAttributes>) -> Text {
  23. if context.isStale {
  24. Text("--")
  25. } else {
  26. Text(context.state.bg)
  27. }
  28. }
  29. @ViewBuilder func trend(context: ActivityViewContext<LiveActivityAttributes>) -> some View {
  30. if context.isStale {
  31. Text("--")
  32. } else {
  33. if let trendSystemImage = context.state.trendSystemImage {
  34. Image(systemName: trendSystemImage)
  35. }
  36. }
  37. }
  38. @ViewBuilder func bgAndTrend(context: ActivityViewContext<LiveActivityAttributes>) -> some View {
  39. if context.isStale {
  40. Text("--")
  41. } else {
  42. Text(context.state.bg)
  43. if let trendSystemImage = context.state.trendSystemImage {
  44. Image(systemName: trendSystemImage)
  45. }
  46. }
  47. }
  48. @ViewBuilder func chart(context: ActivityViewContext<LiveActivityAttributes>) -> some View {
  49. if context.isStale {
  50. Text("--")
  51. } else {
  52. Chart {
  53. ForEach(context.state.chart.indices, id: \.self) { index in
  54. LineMark(
  55. x: .value("Time", context.state.chartDate[index] ?? Date()),
  56. y: .value("Value", context.state.chart[index] ?? 0)
  57. ).foregroundStyle(Color.blue.gradient).symbolSize(12)
  58. }
  59. }
  60. }
  61. }
  62. var body: some WidgetConfiguration {
  63. ActivityConfiguration(for: LiveActivityAttributes.self) { context in
  64. // Lock screen/banner UI goes here
  65. HStack(spacing: 3) {
  66. VStack {
  67. bgLabel(context: context).font(.title)
  68. HStack {
  69. trend(context: context)
  70. changeLabel(context: context).font(.title3)
  71. }
  72. updatedLabel(context: context).font(.caption).foregroundStyle(.black.opacity(0.7))
  73. }
  74. Spacer()
  75. VStack(alignment: .trailing, spacing: 5) {
  76. chart(context: context)
  77. }
  78. }
  79. .privacySensitive()
  80. .imageScale(.small)
  81. .padding(.all, 15)
  82. .background(Color.white.opacity(0.2))
  83. .foregroundColor(Color.black)
  84. .activityBackgroundTint(Color.cyan.opacity(0.2))
  85. .activitySystemActionForegroundColor(Color.black)
  86. } dynamicIsland: { context in
  87. DynamicIsland {
  88. // Expanded UI goes here. Compose the expanded UI through
  89. // various regions, like leading/trailing/center/bottom
  90. DynamicIslandExpandedRegion(.leading) {
  91. HStack(spacing: 3) {
  92. bgAndTrend(context: context)
  93. }.imageScale(.small).font(.title).padding(.leading, 5)
  94. }
  95. DynamicIslandExpandedRegion(.trailing) {
  96. changeLabel(context: context).font(.title).padding(.trailing, 5)
  97. }
  98. DynamicIslandExpandedRegion(.bottom) {
  99. updatedLabel(context: context).font(.caption).foregroundStyle(Color.secondary)
  100. .padding(.bottom, 5)
  101. chart(context: context)
  102. }
  103. } compactLeading: {
  104. HStack(spacing: 1) {
  105. bgAndTrend(context: context)
  106. }.bold().imageScale(.small).padding(.leading, 5)
  107. } compactTrailing: {
  108. changeLabel(context: context).padding(.trailing, 5)
  109. } minimal: {
  110. bgLabel(context: context).bold()
  111. }
  112. .widgetURL(URL(string: "freeaps-x://"))
  113. .keylineTint(Color.cyan.opacity(0.5))
  114. }
  115. }
  116. }
  117. // private extension LiveActivityAttributes {
  118. // static var preview: LiveActivityAttributes {
  119. // LiveActivityAttributes(startDate: Date())
  120. // }
  121. // }
  122. //
  123. // private extension LiveActivityAttributes.ContentState {
  124. // static var test: LiveActivityAttributes.ContentState {
  125. // LiveActivityAttributes.ContentState(bg: "100", trendSystemImage: "arrow.right", change: "+2", date: Date())
  126. // }
  127. // }
  128. //
  129. // #Preview("Notification", as: .content, using: LiveActivityAttributes.preview) {
  130. // LiveActivity()
  131. // } contentStates: {
  132. // LiveActivityAttributes.ContentState.test
  133. // }