|
|
|
|
@ -29,25 +29,34 @@ struct LiveActivityView: View { |
|
|
|
|
|
|
|
|
|
struct LaunchWidgetLiveActivity: Widget { |
|
|
|
|
|
|
|
|
|
fileprivate let now: Date = Date() |
|
|
|
|
|
|
|
|
|
var body: some WidgetConfiguration { |
|
|
|
|
ActivityConfiguration(for: LaunchWidgetAttributes.self) { context in |
|
|
|
|
|
|
|
|
|
// Lock screen/banner UI goes here |
|
|
|
|
VStack(alignment: .leading) { |
|
|
|
|
// TimelineView(.periodic(from: self.now, by: 0.1)) { _ in |
|
|
|
|
|
|
|
|
|
if context.attributes.isTimer { |
|
|
|
|
let range = Date()...context.attributes.date |
|
|
|
|
Text(timerInterval: range, |
|
|
|
|
pauseTime: range.lowerBound) |
|
|
|
|
.font(.title) |
|
|
|
|
} else { |
|
|
|
|
Text(context.attributes.date, style: .timer) |
|
|
|
|
// Lock screen/banner UI goes here |
|
|
|
|
VStack(alignment: .leading) { |
|
|
|
|
|
|
|
|
|
let date: Date = self._date(context: context) |
|
|
|
|
let name: String = self._name(context: context) |
|
|
|
|
|
|
|
|
|
if context.attributes.isCountdown { |
|
|
|
|
let range = Date()...date |
|
|
|
|
Text(timerInterval: range, |
|
|
|
|
pauseTime: range.lowerBound) |
|
|
|
|
.font(.title) |
|
|
|
|
} else { |
|
|
|
|
Text(context.attributes.date, style: .timer) |
|
|
|
|
.font(.title) |
|
|
|
|
} |
|
|
|
|
Text(name.uppercased()) |
|
|
|
|
.font(.callout) |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
Text(context.attributes.name.uppercased()) |
|
|
|
|
.font(.callout) |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// } |
|
|
|
|
.padding() |
|
|
|
|
.monospaced() |
|
|
|
|
.background(Color(white: 0.1)) |
|
|
|
|
@ -60,10 +69,12 @@ struct LaunchWidgetLiveActivity: Widget { |
|
|
|
|
DynamicIslandExpandedRegion(.leading) { |
|
|
|
|
Text(context.attributes.name.uppercased()) |
|
|
|
|
.monospaced() |
|
|
|
|
.padding(.leading, 4.0) |
|
|
|
|
} |
|
|
|
|
DynamicIslandExpandedRegion(.trailing) { |
|
|
|
|
Text(context.attributes.date, style: .timer) |
|
|
|
|
.monospaced() |
|
|
|
|
.padding(.trailing, 4.0) |
|
|
|
|
} |
|
|
|
|
DynamicIslandExpandedRegion(.bottom) { |
|
|
|
|
Button { |
|
|
|
|
@ -76,7 +87,7 @@ struct LaunchWidgetLiveActivity: Widget { |
|
|
|
|
Text(context.attributes.name.uppercased()) |
|
|
|
|
} compactTrailing: { |
|
|
|
|
Group { |
|
|
|
|
if context.attributes.isTimer { |
|
|
|
|
if context.attributes.isCountdown { |
|
|
|
|
let range = Date()...context.attributes.date |
|
|
|
|
Text(timerInterval: range, |
|
|
|
|
pauseTime: range.lowerBound) |
|
|
|
|
@ -85,7 +96,7 @@ struct LaunchWidgetLiveActivity: Widget { |
|
|
|
|
} |
|
|
|
|
}.multilineTextAlignment(.trailing) |
|
|
|
|
} minimal: { |
|
|
|
|
if context.attributes.isTimer { |
|
|
|
|
if context.attributes.isCountdown { |
|
|
|
|
let range = Date()...context.attributes.date |
|
|
|
|
Text(timerInterval: range, |
|
|
|
|
pauseTime: range.lowerBound) |
|
|
|
|
@ -100,9 +111,26 @@ struct LaunchWidgetLiveActivity: Widget { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fileprivate func _name(context: ActivityViewContext<LaunchWidgetAttributes>) -> String { |
|
|
|
|
if let name = context.state.sequence?.currentStep.name { |
|
|
|
|
return name |
|
|
|
|
} else { |
|
|
|
|
return context.attributes.name |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fileprivate func _date(context: ActivityViewContext<LaunchWidgetAttributes>) -> Date { |
|
|
|
|
if let date = context.state.sequence?.currentStep.interval.end { |
|
|
|
|
return date |
|
|
|
|
} else { |
|
|
|
|
return context.attributes.date |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fileprivate func _stop() { |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
struct LaunchWidgetLiveActivity_Previews: PreviewProvider { |
|
|
|
|
@ -110,7 +138,7 @@ struct LaunchWidgetLiveActivity_Previews: PreviewProvider { |
|
|
|
|
static let attributes = LaunchWidgetAttributes( |
|
|
|
|
id: "", |
|
|
|
|
name: "Tea", |
|
|
|
|
date: Date().addingTimeInterval(3600.0), isTimer: true) |
|
|
|
|
date: Date().addingTimeInterval(3600.0), isCountdown: true) |
|
|
|
|
|
|
|
|
|
static let contentState = LaunchWidgetAttributes.ContentState(ended: false) |
|
|
|
|
|
|
|
|
|
|