update
This commit is contained in:
parent
e795fcece6
commit
fb90a13e83
|
@ -25,31 +25,31 @@ enum ConstantsWidget {
|
|||
}()
|
||||
|
||||
// live activity notification widget
|
||||
static let viewWidthLiveActivityNotificationNormal: CGFloat = 200
|
||||
static let viewHeightLiveActivityNotificationNormal: CGFloat = 80 // 100 for normal
|
||||
static let viewWidthLiveActivityNotificationNormal: CGFloat = 180
|
||||
static let viewHeightLiveActivityNotificationNormal: CGFloat = 90
|
||||
static let hoursToShowLiveActivityNotificationNormal: Double = 3
|
||||
static let intervalBetweenXAxisValuesLiveActivityNotificationNormal: Int = 1
|
||||
|
||||
static let viewWidthLiveActivityNotificationLarge: CGFloat = 220
|
||||
static let viewHeightLiveActivityNotificationLarge: CGFloat = 140 // 150 seems to be max size without clipping
|
||||
static let hoursToShowLiveActivityNotificationLarge: Double = 5
|
||||
static let viewWidthLiveActivityNotificationLarge: CGFloat = 360
|
||||
static let viewHeightLiveActivityNotificationLarge: CGFloat = 160 // 150 seems to be max size without clipping
|
||||
static let hoursToShowLiveActivityNotificationLarge: Double = 6
|
||||
static let intervalBetweenXAxisValuesLiveActivityNotificationLarge: Int = 1
|
||||
|
||||
static let viewBackgroundColorLiveActivityNotification = Color.black
|
||||
static let lowHighLineColorLiveActivityNotification = Color(white: 0.7)
|
||||
static let urgentLowHighLineLiveActivityNotification = Color(white: 0.5)
|
||||
static let lowHighLineColorLiveActivityNotification = Color(white: 0.6)
|
||||
static let urgentLowHighLineLiveActivityNotification = Color(white: 0.4)
|
||||
static let xAxisGridLineColorLiveActivityNotification = Color(white: 0.4)
|
||||
static let glucoseCircleDiameterLiveActivityNotification: Double = 36
|
||||
static let relativeYAxisLineSizeLiveActivityNotification: Double = 1
|
||||
static let xAxisLabelOffsetLiveActivityNotification: Double = -10
|
||||
|
||||
// dynamic island bottom (expanded)
|
||||
static let viewWidthDynamicIsland: CGFloat = 320
|
||||
static let viewWidthDynamicIsland: CGFloat = 330
|
||||
static let viewHeightDynamicIsland: CGFloat = 70
|
||||
|
||||
static let viewBackgroundColorDynamicIsland = Color.black
|
||||
static let lowHighLineColorDynamicIsland = Color(white: 0.7)
|
||||
static let urgentLowHighLineColorDynamicIsland = Color(white: 0.5)
|
||||
static let lowHighLineColorDynamicIsland = Color(white: 0.6)
|
||||
static let urgentLowHighLineColorDynamicIsland = Color(white: 0.4)
|
||||
static let xAxisGridLineColorDynamicIsland = Color(white: 0.5)
|
||||
static let hoursToShowDynamicIsland: Double = 12
|
||||
static let intervalBetweenXAxisValuesDynamicIsland: Int = 2
|
||||
|
|
|
@ -77,7 +77,8 @@ struct GlucoseChartView: View {
|
|||
let intervalBetweenAxisValues: Int = glucoseChartWidgetType.intervalBetweenAxisValues(liveActivityNotificationSizeType: liveActivityNotificationSizeType)
|
||||
|
||||
/// first, for each int in mappingArray, we create a Date, starting with the lower hour + 1 hour - we will create 5 in this example, starting with hour 08 (7 + 3600 seconds)
|
||||
let startDateLower = startDate.toLowerHour()
|
||||
let startDateLower = Date(timeIntervalSinceReferenceDate:
|
||||
(startDate.timeIntervalSinceReferenceDate / 3600.0).rounded(.down) * 3600.0)
|
||||
|
||||
let xAxisValues: [Date] = stride(from: 1, to: mappingArray.count + 1, by: intervalBetweenAxisValues).map {
|
||||
startDateLower.addingTimeInterval(Double($0)*3600)
|
||||
|
@ -89,7 +90,8 @@ struct GlucoseChartView: View {
|
|||
|
||||
|
||||
var body: some View {
|
||||
let domain = 40 ... max(bgReadingValues.max() ?? 400, urgentHighLimitInMgDl)
|
||||
|
||||
let domain = (min((bgReadingValues.min() ?? 40), urgentLowLimitInMgDl) - 6) ... (max((bgReadingValues.max() ?? 400), urgentHighLimitInMgDl) + 6)
|
||||
|
||||
Chart {
|
||||
if domain.contains(urgentLowLimitInMgDl) {
|
||||
|
@ -123,24 +125,47 @@ struct GlucoseChartView: View {
|
|||
.symbolSize(glucoseChartWidgetType.glucoseCircleDiameter)
|
||||
.foregroundStyle(bgColor(bgValueInMgDl: bgReadingValues[index]))
|
||||
}
|
||||
|
||||
// add a phantom glucose point five minutes after the end of any BG values just to give more context
|
||||
PointMark(x: .value("Time", Date().addingTimeInterval(5 * 60)),
|
||||
y: .value("BG", 100))
|
||||
.symbol(Circle())
|
||||
.symbolSize(glucoseChartWidgetType.glucoseCircleDiameter)
|
||||
.foregroundStyle(.clear)
|
||||
}
|
||||
.chartXAxis {
|
||||
// https://developer.apple.com/documentation/charts/customizing-axes-in-swift-charts
|
||||
AxisMarks(values: xAxisValues()) {
|
||||
|
||||
// AxisMarks(values: xAxisValues()) { value in
|
||||
//
|
||||
// if let v = value.as(Date.self) {
|
||||
// AxisValueLabel {
|
||||
// Text(v.formatted(.dateTime.hour()))
|
||||
// .foregroundStyle(Color.white)
|
||||
// }
|
||||
// //.offset(x: glucoseChartWidgetType.xAxisLabelOffset)
|
||||
//
|
||||
// AxisGridLine()
|
||||
// .foregroundStyle(glucoseChartWidgetType.xAxisGridLineColor)
|
||||
// }
|
||||
// }
|
||||
|
||||
AxisMarks(values: .automatic(desiredCount: Int(glucoseChartWidgetType.hoursToShow(liveActivityNotificationSizeType: liveActivityNotificationSizeType)))) {
|
||||
if let v = $0.as(Date.self) {
|
||||
AxisValueLabel {
|
||||
Text(v.formatted(.dateTime.hour()))
|
||||
.foregroundStyle(Color.white)
|
||||
}
|
||||
.offset(x: glucoseChartWidgetType.xAxisLabelOffset)
|
||||
// AxisValueLabel {
|
||||
// Text(v.formatted(.dateTime.hour()))
|
||||
// .foregroundStyle(Color.white)
|
||||
// }
|
||||
// .offset(x: glucoseChartWidgetType.xAxisLabelOffset)
|
||||
AxisGridLine()
|
||||
.foregroundStyle(glucoseChartWidgetType.xAxisGridLineColor)
|
||||
}
|
||||
}
|
||||
}
|
||||
//.background(Color.purple)
|
||||
.chartYAxis(.hidden)
|
||||
.chartYScale(domain: domain)
|
||||
.frame(width: glucoseChartWidgetType.viewSize(liveActivityNotificationSizeType: liveActivityNotificationSizeType).width, height: glucoseChartWidgetType.viewSize(liveActivityNotificationSizeType: liveActivityNotificationSizeType).height)
|
||||
// .padding(.top, 20)
|
||||
// .padding(.bottom, 20)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,8 +38,6 @@ struct XDripWidgetAttributes: ActivityAttributes {
|
|||
var bgUnitString: String
|
||||
var bgValueStringInUserChosenUnit: String
|
||||
|
||||
//var bgReadings: [BgReading]
|
||||
|
||||
init(bgReadingValues: [Double], bgReadingDates: [Date], isMgDl: Bool, slopeOrdinal: Int, deltaChangeInMgDl: Double?, urgentLowLimitInMgDl: Double, lowLimitInMgDl: Double, highLimitInMgDl: Double, urgentHighLimitInMgDl: Double, updatedDate: Date, liveActivityNotificationSizeTypeAsInt: Int) {
|
||||
|
||||
// these are the "passed in" stateful values used to initialize
|
||||
|
@ -79,17 +77,18 @@ struct XDripWidgetAttributes: ActivityAttributes {
|
|||
|
||||
/// Show the bg event title if relevant
|
||||
/// - Returns: a localized string such as "HIGH" or "LOW" as required
|
||||
func getBgTitle() -> String? {
|
||||
@available(iOS 16, *)
|
||||
func getBgTitle() -> LocalizedStringResource {
|
||||
if bgValueInMgDl >= urgentHighLimitInMgDl {
|
||||
return Texts_Widget.urgentHigh
|
||||
return "\(Texts_Widget.urgentHigh)"
|
||||
} else if bgValueInMgDl >= highLimitInMgDl {
|
||||
return Texts_Widget.high
|
||||
return "\(Texts_Widget.high)"
|
||||
} else if bgValueInMgDl <= lowLimitInMgDl {
|
||||
return Texts_Widget.low
|
||||
return "\(Texts_Widget.low)"
|
||||
} else if bgValueInMgDl <= urgentLowLimitInMgDl {
|
||||
return Texts_Widget.urgentLow
|
||||
return "\(Texts_Widget.urgentLow)"
|
||||
} else {
|
||||
return nil
|
||||
return "TEST"
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -148,18 +147,47 @@ struct XDripWidgetAttributes: ActivityAttributes {
|
|||
}
|
||||
|
||||
func deltaChangeFormatted(font: Font) -> some View {
|
||||
HStack(spacing: 4) {
|
||||
HStack(alignment: .firstTextBaseline, spacing: 4) {
|
||||
Text(getDeltaChangeStringInUserChosenUnit())
|
||||
.font(font).bold()
|
||||
.foregroundStyle(Color(white: 0.9))
|
||||
.minimumScaleFactor(0.2)
|
||||
.lineLimit(1)
|
||||
Text(bgUnitString)
|
||||
.font(font)
|
||||
.foregroundStyle(Color(white: 0.5))
|
||||
.minimumScaleFactor(0.2)
|
||||
.lineLimit(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// func remindUserToOpenApp(eventStartDate: Date) -> Bool {
|
||||
// return eventStartDate < Date().addingTimeInterval(-3600 * 0.2) ? true : false
|
||||
// }
|
||||
|
||||
func placeTextAtBottomOfWidget(glucoseChartWidgetType: GlucoseChartWidgetType) -> Bool {
|
||||
|
||||
// first see at which index in bgReadingDates the BG value is after one hour
|
||||
var firstIndexForWidgetType = 0
|
||||
var index = 0
|
||||
|
||||
for _ in bgReadingValues {
|
||||
if bgReadingDates[index] > Date().addingTimeInterval((-glucoseChartWidgetType.hoursToShow(liveActivityNotificationSizeType: LiveActivityNotificationSizeType(rawValue: liveActivityNotificationSizeTypeAsInt) ?? .normal) * 60 * 60) + 3600) {
|
||||
firstIndexForWidgetType = index
|
||||
}
|
||||
index += 1
|
||||
}
|
||||
|
||||
// then get the bg value of that index in the bgValues array
|
||||
// if it is higher than the user's high limit, then we can assume that the data will be hidden
|
||||
// by the text (bg value, trend + delta), so return true to show the text at the bottom of the view
|
||||
if bgReadingValues[firstIndexForWidgetType] >= highLimitInMgDl {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// when was the live activity event started? We check this on each update cycle and dismiss/recreate it before the 8-hour limit.
|
||||
var eventStartDate: Date
|
||||
// no static data is needed
|
||||
}
|
||||
|
|
|
@ -13,13 +13,137 @@ import SwiftUI
|
|||
@available(iOSApplicationExtension 16.2, *)
|
||||
struct XDripWidgetLiveActivity: Widget {
|
||||
|
||||
let glucoseChartWidgetType: GlucoseChartWidgetType = .dynamicIsland
|
||||
|
||||
var body: some WidgetConfiguration {
|
||||
|
||||
ActivityConfiguration(for: XDripWidgetAttributes.self) { context in
|
||||
|
||||
LiveActivityView(state: context.state)
|
||||
// Lock screen/banner UI goes here
|
||||
|
||||
if context.state.liveActivityNotificationSizeTypeAsInt == 0 {
|
||||
|
||||
// 0 = normal size chart
|
||||
HStack(spacing: 20) {
|
||||
VStack {
|
||||
Text("\(context.state.bgValueStringInUserChosenUnit)\(context.state.trendArrow())")
|
||||
.font(.system(size: 50)).bold()
|
||||
.foregroundStyle(context.state.getBgColor())
|
||||
.minimumScaleFactor(0.1)
|
||||
.lineLimit(1)
|
||||
|
||||
context.state.deltaChangeFormatted(font: .title2)
|
||||
.minimumScaleFactor(0.1)
|
||||
.lineLimit(1)
|
||||
}
|
||||
.padding(4)
|
||||
|
||||
// ZStack {
|
||||
GlucoseChartView(bgReadingValues: context.state.bgReadingValues, bgReadingDates: context.state.bgReadingDates, glucoseChartWidgetType: .liveActivityNotification, isMgDl: context.state.isMgDl, urgentLowLimitInMgDl: context.state.urgentLowLimitInMgDl, lowLimitInMgDl: context.state.lowLimitInMgDl, highLimitInMgDl: context.state.highLimitInMgDl, urgentHighLimitInMgDl: context.state.urgentHighLimitInMgDl, liveActivityNotificationSizeType: LiveActivityNotificationSizeType(rawValue: context.state.liveActivityNotificationSizeTypeAsInt) ?? .normal)
|
||||
|
||||
//Text(context.attributes.eventStartDate.formatted(date: .omitted, time: .shortened))
|
||||
|
||||
/*
|
||||
if context.state.remindUserToOpenApp(eventStartDate: context.attributes.eventStartDate) {
|
||||
VStack(alignment: .center) {
|
||||
Spacer()
|
||||
Text("Please open xDrip4iOS")
|
||||
.font(.caption)
|
||||
.minimumScaleFactor(0.1)
|
||||
.foregroundStyle(.black)
|
||||
.multilineTextAlignment(.center)
|
||||
.lineLimit(1)
|
||||
.padding(EdgeInsets(top: 4, leading: 8, bottom: 4, trailing: 8))
|
||||
.background(Color(white: 0.8, opacity: 0.8))
|
||||
.cornerRadius(15)
|
||||
Spacer()
|
||||
}
|
||||
.padding(8)
|
||||
}
|
||||
*/
|
||||
// }
|
||||
}
|
||||
.activityBackgroundTint(.black)
|
||||
.padding(6)
|
||||
|
||||
} else if context.state.liveActivityNotificationSizeTypeAsInt == 1 {
|
||||
|
||||
// 1 = minimal widget with no chart
|
||||
|
||||
HStack(alignment: .center) {
|
||||
|
||||
Text("\(context.state.bgValueStringInUserChosenUnit)\(context.state.trendArrow())")
|
||||
.font(.largeTitle).bold()
|
||||
.foregroundStyle(context.state.getBgColor())
|
||||
.minimumScaleFactor(0.1)
|
||||
.lineLimit(1)
|
||||
|
||||
Spacer()
|
||||
|
||||
context.state.deltaChangeFormatted(font: .title)
|
||||
.minimumScaleFactor(0.1)
|
||||
.lineLimit(1)
|
||||
}
|
||||
.activityBackgroundTint(.black)
|
||||
.padding(15)
|
||||
|
||||
} else {
|
||||
|
||||
// 2 = large chart
|
||||
|
||||
ZStack {
|
||||
|
||||
GlucoseChartView(bgReadingValues: context.state.bgReadingValues, bgReadingDates: context.state.bgReadingDates, glucoseChartWidgetType: .liveActivityNotification, isMgDl: context.state.isMgDl, urgentLowLimitInMgDl: context.state.urgentLowLimitInMgDl, lowLimitInMgDl: context.state.lowLimitInMgDl, highLimitInMgDl: context.state.highLimitInMgDl, urgentHighLimitInMgDl: context.state.urgentHighLimitInMgDl, liveActivityNotificationSizeType: LiveActivityNotificationSizeType(rawValue: context.state.liveActivityNotificationSizeTypeAsInt) ?? .normal)
|
||||
|
||||
//Text(context.attributes.eventStartDate.formatted(date: .omitted, time: .shortened))
|
||||
|
||||
VStack {
|
||||
|
||||
if context.state.placeTextAtBottomOfWidget(glucoseChartWidgetType: .liveActivityNotification) {
|
||||
Spacer()
|
||||
}
|
||||
|
||||
HStack(alignment: .firstTextBaseline) {
|
||||
Text("\(context.state.bgValueStringInUserChosenUnit)\(context.state.trendArrow()) ")
|
||||
.font(.title2).bold()
|
||||
.foregroundStyle(context.state.getBgColor())
|
||||
|
||||
context.state.deltaChangeFormatted(font: .title3)
|
||||
}
|
||||
.padding(EdgeInsets(top: 4, leading: 8, bottom: 4, trailing: 8))
|
||||
.background(Color(white: 0, opacity: 0.7))
|
||||
.cornerRadius(20)
|
||||
|
||||
if !context.state.placeTextAtBottomOfWidget(glucoseChartWidgetType: .liveActivityNotification) {
|
||||
Spacer()
|
||||
}
|
||||
|
||||
// if let bgTitle = state.getBgTitle() {
|
||||
// Text(bgTitle)
|
||||
// .foregroundStyle(state.getBgColor())
|
||||
// .font(.subheadline).bold()
|
||||
// .multilineTextAlignment(.center)
|
||||
// }
|
||||
}
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.padding(6)
|
||||
/*
|
||||
if context.state.remindUserToOpenApp(eventStartDate: context.attributes.eventStartDate) {
|
||||
VStack(alignment: .center) {
|
||||
Spacer()
|
||||
Text("Live activity ending soon\nPlease open xDrip4iOS")
|
||||
.font(.footnote).bold()
|
||||
.foregroundStyle(.black)
|
||||
.multilineTextAlignment(.center)
|
||||
.padding(EdgeInsets(top: 6, leading: 10, bottom: 6, trailing: 10))
|
||||
.background(Color(white: 0.8, opacity: 0.8))
|
||||
.cornerRadius(15)
|
||||
Spacer()
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
.activityBackgroundTint(.black)
|
||||
}
|
||||
|
||||
} dynamicIsland: { context in
|
||||
|
||||
|
@ -28,24 +152,29 @@ struct XDripWidgetLiveActivity: Widget {
|
|||
.font(.largeTitle).bold()
|
||||
.foregroundStyle(context.state.getBgColor())
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center)
|
||||
.minimumScaleFactor(0.1)
|
||||
.lineLimit(1)
|
||||
}
|
||||
DynamicIslandExpandedRegion(.trailing) {
|
||||
context.state.deltaChangeFormatted(font: .title2)
|
||||
context.state.deltaChangeFormatted(font: .title)
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center)
|
||||
}
|
||||
DynamicIslandExpandedRegion(.bottom) {
|
||||
|
||||
GlucoseChartView(bgReadingValues: context.state.bgReadingValues, bgReadingDates: context.state.bgReadingDates, glucoseChartWidgetType: glucoseChartWidgetType, isMgDl: context.state.isMgDl, urgentLowLimitInMgDl: context.state.urgentLowLimitInMgDl, lowLimitInMgDl: context.state.lowLimitInMgDl, highLimitInMgDl: context.state.highLimitInMgDl, urgentHighLimitInMgDl: context.state.urgentHighLimitInMgDl, liveActivityNotificationSizeType: LiveActivityNotificationSizeType(rawValue: context.state.liveActivityNotificationSizeTypeAsInt) ?? .normal)
|
||||
GlucoseChartView(bgReadingValues: context.state.bgReadingValues, bgReadingDates: context.state.bgReadingDates, glucoseChartWidgetType: .dynamicIsland, isMgDl: context.state.isMgDl, urgentLowLimitInMgDl: context.state.urgentLowLimitInMgDl, lowLimitInMgDl: context.state.lowLimitInMgDl, highLimitInMgDl: context.state.highLimitInMgDl, urgentHighLimitInMgDl: context.state.urgentHighLimitInMgDl, liveActivityNotificationSizeType: LiveActivityNotificationSizeType(rawValue: context.state.liveActivityNotificationSizeTypeAsInt) ?? .normal)
|
||||
|
||||
}
|
||||
} compactLeading: {
|
||||
Text("\(context.state.bgValueStringInUserChosenUnit)\(context.state.trendArrow())")
|
||||
.foregroundStyle(context.state.getBgColor())
|
||||
.minimumScaleFactor(0.1)
|
||||
} compactTrailing: {
|
||||
Text(context.state.getDeltaChangeStringInUserChosenUnit())
|
||||
.minimumScaleFactor(0.1)
|
||||
} minimal: {
|
||||
Text(context.state.bgValueStringInUserChosenUnit)
|
||||
.foregroundStyle(context.state.getBgColor())
|
||||
.minimumScaleFactor(0.1)
|
||||
}
|
||||
.widgetURL(URL(string: "xdripswift"))
|
||||
.keylineTint(context.state.getBgColor())
|
||||
|
@ -55,85 +184,15 @@ struct XDripWidgetLiveActivity: Widget {
|
|||
|
||||
}
|
||||
|
||||
@available(iOSApplicationExtension 16.2, *)
|
||||
struct LiveActivityView: View {
|
||||
|
||||
let state: XDripWidgetAttributes.ContentState
|
||||
let glucoseChartWidgetType: GlucoseChartWidgetType = .liveActivityNotification
|
||||
|
||||
var body: some View {
|
||||
// Lock screen/banner UI goes here
|
||||
|
||||
if state.liveActivityNotificationSizeTypeAsInt == 0 {
|
||||
// 0 = normal size chart
|
||||
|
||||
HStack(spacing: 20) {
|
||||
VStack(spacing: 10) {
|
||||
Text("\(state.bgValueStringInUserChosenUnit)\(state.trendArrow())")
|
||||
.font(.largeTitle).bold()
|
||||
.foregroundStyle(state.getBgColor())
|
||||
|
||||
state.deltaChangeFormatted(font: .title2)
|
||||
}
|
||||
|
||||
GlucoseChartView(bgReadingValues: state.bgReadingValues, bgReadingDates: state.bgReadingDates, glucoseChartWidgetType: glucoseChartWidgetType, isMgDl: state.isMgDl, urgentLowLimitInMgDl: state.urgentLowLimitInMgDl, lowLimitInMgDl: state.lowLimitInMgDl, highLimitInMgDl: state.highLimitInMgDl, urgentHighLimitInMgDl: state.urgentHighLimitInMgDl, liveActivityNotificationSizeType: LiveActivityNotificationSizeType(rawValue: state.liveActivityNotificationSizeTypeAsInt) ?? .normal)
|
||||
|
||||
}
|
||||
.activityBackgroundTint(.black)
|
||||
.padding(10)
|
||||
|
||||
} else if state.liveActivityNotificationSizeTypeAsInt == 1 {
|
||||
// 1 = minimal widget with no chart
|
||||
|
||||
HStack {
|
||||
|
||||
Text("\(state.bgValueStringInUserChosenUnit)\(state.trendArrow())")
|
||||
.font(.largeTitle).bold()
|
||||
.foregroundStyle(state.getBgColor())
|
||||
|
||||
Spacer()
|
||||
|
||||
if let bgTitle = state.getBgTitle() {
|
||||
Text(bgTitle)
|
||||
.foregroundStyle(state.getBgColor())
|
||||
.font(.title2).bold()
|
||||
.multilineTextAlignment(.center)
|
||||
}
|
||||
|
||||
Spacer()
|
||||
|
||||
state.deltaChangeFormatted(font: .title2)
|
||||
}
|
||||
.activityBackgroundTint(.black)
|
||||
.padding(15)
|
||||
|
||||
} else {
|
||||
// 2 = large widget with no chart
|
||||
|
||||
HStack(spacing: 10) {
|
||||
VStack(spacing: 10) {
|
||||
Text("\(state.bgValueStringInUserChosenUnit)\(state.trendArrow())")
|
||||
.font(.title).bold()
|
||||
.foregroundStyle(state.getBgColor())
|
||||
|
||||
state.deltaChangeFormatted(font: .title3)
|
||||
|
||||
if let bgTitle = state.getBgTitle() {
|
||||
Text(bgTitle)
|
||||
.foregroundStyle(state.getBgColor())
|
||||
.font(.subheadline).bold()
|
||||
.multilineTextAlignment(.center)
|
||||
}
|
||||
}
|
||||
|
||||
GlucoseChartView(bgReadingValues: state.bgReadingValues, bgReadingDates: state.bgReadingDates, glucoseChartWidgetType: glucoseChartWidgetType, isMgDl: state.isMgDl, urgentLowLimitInMgDl: state.urgentLowLimitInMgDl, lowLimitInMgDl: state.lowLimitInMgDl, highLimitInMgDl: state.highLimitInMgDl, urgentHighLimitInMgDl: state.urgentHighLimitInMgDl, liveActivityNotificationSizeType: LiveActivityNotificationSizeType(rawValue: state.liveActivityNotificationSizeTypeAsInt) ?? .normal)
|
||||
|
||||
}
|
||||
.activityBackgroundTint(.black)
|
||||
.padding(10)
|
||||
}
|
||||
}
|
||||
}
|
||||
//@available(iOSApplicationExtension 16.2, *)
|
||||
//struct LiveActivityView: View {
|
||||
//
|
||||
// let state: XDripWidgetAttributes.ContentState
|
||||
// let glucoseChartWidgetType: GlucoseChartWidgetType = .liveActivityNotification
|
||||
//
|
||||
// var body: some View {
|
||||
// }
|
||||
//}
|
||||
|
||||
@available(iOS 16.2, *)
|
||||
struct XDripWidgetLiveActivity_Previews: PreviewProvider {
|
||||
|
@ -143,9 +202,9 @@ struct XDripWidgetLiveActivity_Previews: PreviewProvider {
|
|||
let endDate = Date()
|
||||
let startDate = endDate.addingTimeInterval(-3600 * 12)
|
||||
var currentDate = startDate
|
||||
|
||||
|
||||
var dateArray: [Date] = []
|
||||
|
||||
|
||||
while currentDate < endDate {
|
||||
dateArray.append(currentDate)
|
||||
currentDate = currentDate.addingTimeInterval(60 * 5)
|
||||
|
@ -162,14 +221,17 @@ struct XDripWidgetLiveActivity_Previews: PreviewProvider {
|
|||
|
||||
for index in bgValueArray.indices {
|
||||
|
||||
if currentValue < 70 {
|
||||
increaseValues = true
|
||||
} else if currentValue > 180 {
|
||||
increaseValues = false
|
||||
}
|
||||
let randomValue = Double(Int.random(in: -10..<10))
|
||||
|
||||
let randomValue = Double(Int.random(in: 0..<20))
|
||||
bgValueArray[index] = currentValue + (increaseValues ? randomValue : -randomValue)
|
||||
if currentValue < 80 {
|
||||
increaseValues = true
|
||||
bgValueArray[index] = currentValue + abs(randomValue)
|
||||
} else if currentValue > 160 {
|
||||
increaseValues = false
|
||||
bgValueArray[index] = currentValue - abs(randomValue)
|
||||
} else {
|
||||
bgValueArray[index] = currentValue + (increaseValues ? randomValue : -randomValue)
|
||||
}
|
||||
currentValue = bgValueArray[index]
|
||||
}
|
||||
|
||||
|
@ -178,9 +240,9 @@ struct XDripWidgetLiveActivity_Previews: PreviewProvider {
|
|||
}
|
||||
|
||||
|
||||
static let attributes = XDripWidgetAttributes(eventStartDate: Date().addingTimeInterval(-1000))
|
||||
static let attributes = XDripWidgetAttributes() //(eventStartDate: Date().addingTimeInterval(-1000))
|
||||
|
||||
static let contentState = XDripWidgetAttributes.ContentState(bgReadingValues: bgValueArray(), bgReadingDates: bgDateArray(), isMgDl: true, slopeOrdinal:5, deltaChangeInMgDl: -2, urgentLowLimitInMgDl: 70, lowLimitInMgDl: 80, highLimitInMgDl: 140, urgentHighLimitInMgDl: 180, updatedDate: Date(), liveActivityNotificationSizeTypeAsInt: 2)
|
||||
static let contentState = XDripWidgetAttributes.ContentState(bgReadingValues: bgValueArray(), bgReadingDates: bgDateArray(), isMgDl: true, slopeOrdinal:5, deltaChangeInMgDl: -2, urgentLowLimitInMgDl: 70, lowLimitInMgDl: 80, highLimitInMgDl: 140, urgentHighLimitInMgDl: 180, updatedDate: Date(), liveActivityNotificationSizeTypeAsInt: 0)
|
||||
|
||||
static var previews: some View {
|
||||
attributes
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
import Foundation
|
||||
import ActivityKit
|
||||
import OSLog
|
||||
import SwiftUI
|
||||
|
||||
@available(iOS 16.2, *)
|
||||
public final class LiveActivityManager {
|
||||
|
@ -21,7 +22,7 @@ public final class LiveActivityManager {
|
|||
static let shared = LiveActivityManager()
|
||||
|
||||
private init() {
|
||||
eventAttributes = XDripWidgetAttributes(eventStartDate: Date())
|
||||
eventAttributes = XDripWidgetAttributes() //eventStartDate: Date())
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -32,28 +33,28 @@ extension LiveActivityManager {
|
|||
|
||||
/// start or update the live activity based upon whether it currently exists or not
|
||||
/// - Parameter contentState: the contentState to show
|
||||
/// - Parameter forceRestart: will force the current live activity to end and a new one will be started
|
||||
func runActivity(contentState: XDripWidgetAttributes.ContentState, forceRestart: Bool) {
|
||||
|
||||
trace("In runActivity", log: self.log, category: ConstantsLog.categoryLiveActivityManager, type: .info)
|
||||
trace("in runActivity", log: self.log, category: ConstantsLog.categoryLiveActivityManager, type: .info)
|
||||
|
||||
// checking whether 'Live activities' is enabled for the app in settings
|
||||
if ActivityAuthorizationInfo().areActivitiesEnabled {
|
||||
if eventActivity == nil {
|
||||
trace(" eventActivity == nil, trying to start new activity", log: self.log, category: ConstantsLog.categoryLiveActivityManager, type: .info)
|
||||
print("Starting new Live Activity")
|
||||
trace(" starting new live activity", log: self.log, category: ConstantsLog.categoryLiveActivityManager, type: .info)
|
||||
|
||||
startActivity(contentState: contentState)
|
||||
} else if forceRestart {
|
||||
print("ending current activity and starting a new one")
|
||||
trace(" eventActivity != nil, will attempt to end the current activity and start a new one", log: self.log, category: ConstantsLog.categoryLiveActivityManager, type: .info)
|
||||
print("Restarting Live Activity")
|
||||
trace(" restarting live activity", log: self.log, category: ConstantsLog.categoryLiveActivityManager, type: .info)
|
||||
|
||||
Task {
|
||||
endActivity()
|
||||
|
||||
await endActivity()
|
||||
startActivity(contentState: contentState)
|
||||
}
|
||||
} else {
|
||||
trace(" eventActivity != nil, trying to update existing activity", log: self.log, category: ConstantsLog.categoryLiveActivityManager, type: .info)
|
||||
print("Updating Live Activity")
|
||||
trace(" updating live activity", log: self.log, category: ConstantsLog.categoryLiveActivityManager, type: .info)
|
||||
|
||||
Task {
|
||||
await updateActivity(to: contentState)
|
||||
|
@ -70,7 +71,6 @@ extension LiveActivityManager {
|
|||
let content = ActivityContent(state: contentState, staleDate: nil, relevanceScore: 1.0)
|
||||
|
||||
do {
|
||||
print("Trying to start new live activity")
|
||||
eventActivity = try Activity.request(
|
||||
attributes: eventAttributes,
|
||||
content: content,
|
||||
|
@ -80,7 +80,7 @@ extension LiveActivityManager {
|
|||
print("New live activity started: \(String(describing: eventActivity?.id))")
|
||||
|
||||
let idString = "\(String(describing: eventActivity?.id))"
|
||||
trace("New live activity started: %{public}@", log: self.log, category: ConstantsLog.categoryLiveActivityManager, type: .info, idString)
|
||||
trace("new live activity started: %{public}@", log: self.log, category: ConstantsLog.categoryLiveActivityManager, type: .info, idString)
|
||||
} catch {
|
||||
print(error.localizedDescription)
|
||||
|
||||
|
@ -102,34 +102,26 @@ extension LiveActivityManager {
|
|||
|
||||
startActivity(contentState: contentState)
|
||||
}
|
||||
return
|
||||
|
||||
} else {
|
||||
|
||||
// check if the activity is not about to be orphaned by iOS (after 8 hours) and left on the screen with the initial state. If it is then end it.
|
||||
if eventAttributes.eventStartDate > Date().addingTimeInterval(-3600 * 8) {
|
||||
|
||||
await eventActivity?.update(
|
||||
ActivityContent<XDripWidgetAttributes.ContentState>(
|
||||
state: contentState,
|
||||
staleDate: Date().addingTimeInterval(10)
|
||||
)
|
||||
)
|
||||
|
||||
} else {
|
||||
|
||||
trace("Live activity is 8 hours old so will no longer be able to be updated. Ending activity ", log: self.log, category: ConstantsLog.categoryLiveActivityManager, type: .info)
|
||||
|
||||
endActivity()
|
||||
|
||||
startActivity(contentState: contentState)
|
||||
|
||||
}
|
||||
//let alertConfiguration = AlertConfiguration(title: "BG Alert", body: contentState.getBgTitle(), sound: .default)
|
||||
let updatedContent = ActivityContent(state: contentState, staleDate: nil)
|
||||
|
||||
// if contentState.getBgTitle() != "" {
|
||||
// print("Triggering Live Activity alert for \(String(describing: contentState.getBgTitle()))")
|
||||
// trace("triggering live activity alert for: %{public}@", log: self.log, category: ConstantsLog.categoryLiveActivityManager, type: .info, String(describing: contentState.getBgTitle()))
|
||||
//
|
||||
// await eventActivity?.update(updatedContent, alertConfiguration: alertConfiguration)
|
||||
// } else {
|
||||
// await eventActivity?.update(updatedContent)
|
||||
// }
|
||||
|
||||
await eventActivity?.update(updatedContent)
|
||||
}
|
||||
}
|
||||
|
||||
/// end the live activity if it is being shown, do nothing if there is no eventyActivity
|
||||
func endActivity() {
|
||||
func endActivity() async {
|
||||
|
||||
if eventActivity != nil {
|
||||
Task {
|
||||
|
@ -140,9 +132,9 @@ extension LiveActivityManager {
|
|||
trace("Ending live activity: %{public}@", log: self.log, category: ConstantsLog.categoryLiveActivityManager, type: .info, idString)
|
||||
|
||||
await activity.end(nil, dismissalPolicy: .immediate)
|
||||
eventActivity = nil
|
||||
}
|
||||
}
|
||||
eventActivity = nil
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -163,10 +155,11 @@ extension LiveActivityManager {
|
|||
trace("Ending live activity: %{public}@", log: self.log, category: ConstantsLog.categoryLiveActivityManager, type: .info, idString)
|
||||
|
||||
await activity.end(nil, dismissalPolicy: .immediate)
|
||||
eventActivity = nil
|
||||
}
|
||||
semaphore.signal()
|
||||
}
|
||||
semaphore.wait()
|
||||
|
||||
eventActivity = nil
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3524,8 +3524,6 @@ final class RootViewController: UIViewController, ObservableObject {
|
|||
// also take advantage to just skip the rest of the function if they have live activities disabled
|
||||
var showLiveActivity: Bool = true //!(!UserDefaults.standard.isMaster || UserDefaults.standard.liveActivityType == .disabled)
|
||||
|
||||
let forceRestart = forceRestart
|
||||
|
||||
if let bgReadingsAccessor = bgReadingsAccessor, showLiveActivity {
|
||||
|
||||
// get 2 last Readings, with a calculatedValue
|
||||
|
|
Loading…
Reference in New Issue