Repo created
This commit is contained in:
parent
4af19165ec
commit
68073add76
12458 changed files with 12350765 additions and 2 deletions
|
|
@ -0,0 +1,9 @@
|
|||
import SwiftUI
|
||||
|
||||
struct AppLogo: View {
|
||||
var body: some View {
|
||||
Image("comaps")
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
import ActivityKit
|
||||
import SwiftUI
|
||||
|
||||
@available(iOS 16.2, *)
|
||||
final class LiveActivityManager {
|
||||
static func startActivity<T: ActivityAttributes>(_ attributes: T, content: ActivityContent<T.ContentState>) throws -> Activity<T> {
|
||||
return try Activity.request(attributes: attributes, content: content, pushType: nil)
|
||||
}
|
||||
|
||||
static func update<T: ActivityAttributes>(_ activity: Activity<T>, content: ActivityContent<T.ContentState>) {
|
||||
Task {
|
||||
await activity.update(content)
|
||||
}
|
||||
}
|
||||
|
||||
static func stop(_ activity: Activity<some ActivityAttributes>) {
|
||||
// semaphore is used for removing the activity during the app termination
|
||||
let semaphore = DispatchSemaphore(value: 0)
|
||||
Task {
|
||||
await activity.end(nil, dismissalPolicy: .immediate)
|
||||
semaphore.signal()
|
||||
}
|
||||
semaphore.wait()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
import SwiftUI
|
||||
|
||||
struct StatisticDetailView: View {
|
||||
private let title: String
|
||||
private let subtitle: String
|
||||
|
||||
init(title: String, subtitle: String) {
|
||||
self.title = title
|
||||
self.subtitle = subtitle
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading) {
|
||||
Text(title)
|
||||
.contentTransition(.numericText())
|
||||
.font(.system(size: 14, weight: .bold).monospacedDigit())
|
||||
.minimumScaleFactor(0.5)
|
||||
.lineLimit(1)
|
||||
.foregroundStyle(.white)
|
||||
Text(subtitle)
|
||||
.font(.system(size: 10))
|
||||
.minimumScaleFactor(0.5)
|
||||
.lineLimit(2)
|
||||
.multilineTextAlignment(.center)
|
||||
.foregroundStyle(.white)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
import SwiftUI
|
||||
|
||||
struct StatisticValueView: View {
|
||||
private let value: String
|
||||
|
||||
init(_ value: String) {
|
||||
self.value = value
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
Text(value)
|
||||
.contentTransition(.numericText())
|
||||
.minimumScaleFactor(0.1)
|
||||
.font(.title3.bold().monospacedDigit())
|
||||
.foregroundStyle(.white)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
import ActivityKit
|
||||
import AppIntents
|
||||
|
||||
struct TrackRecordingLiveActivityAttributes: ActivityAttributes {
|
||||
struct ContentState: Codable, Hashable {
|
||||
struct StatisticsViewModel: Codable, Hashable {
|
||||
let key: String
|
||||
let value: String
|
||||
}
|
||||
let duration: StatisticsViewModel
|
||||
let distance: StatisticsViewModel
|
||||
let ascent: StatisticsViewModel
|
||||
let descent: StatisticsViewModel
|
||||
let maxElevation: StatisticsViewModel
|
||||
let minElevation: StatisticsViewModel
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
import WidgetKit
|
||||
import SwiftUI
|
||||
|
||||
struct TrackRecordingLiveActivityConfiguration: Widget {
|
||||
@Environment(\.colorScheme) private var colorScheme
|
||||
|
||||
var body: some WidgetConfiguration {
|
||||
ActivityConfiguration(for: TrackRecordingLiveActivityAttributes.self) { context in
|
||||
TrackRecordingLiveActivityView(state: context.state)
|
||||
} dynamicIsland: { context in
|
||||
DynamicIsland {
|
||||
DynamicIslandExpandedRegion(.center) {
|
||||
// TODO: Implement the expanded view
|
||||
}
|
||||
} compactLeading: {
|
||||
AppLogo()
|
||||
} compactTrailing: {
|
||||
StatisticValueView(context.state.duration.value)
|
||||
} minimal: {
|
||||
// TODO: Implement the minimal view
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
import SwiftUI
|
||||
import WidgetKit
|
||||
|
||||
#if canImport(ActivityKit)
|
||||
|
||||
struct TrackRecordingLiveActivityView: View {
|
||||
let state: TrackRecordingLiveActivityAttributes.ContentState
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading, spacing: 12) {
|
||||
HStack(alignment: .top, spacing: 24) {
|
||||
StatisticValueView(state.duration.value)
|
||||
StatisticValueView(state.distance.value)
|
||||
Spacer()
|
||||
AppLogo()
|
||||
.frame(width: 20, height: 20)
|
||||
}
|
||||
.padding([.top, .leading, .trailing], 16)
|
||||
HStack(alignment: .top, spacing: 20) {
|
||||
StatisticDetailView(title: state.ascent.value, subtitle: state.ascent.key)
|
||||
StatisticDetailView(title: state.descent.value, subtitle: state.descent.key)
|
||||
StatisticDetailView(title: state.maxElevation.value, subtitle: state.maxElevation.key)
|
||||
StatisticDetailView(title: state.minElevation.value, subtitle: state.minElevation.key)
|
||||
}
|
||||
.padding([.leading, .trailing, .bottom], 16)
|
||||
}
|
||||
.activityBackgroundTint(.black.opacity(0.2))
|
||||
// Uncomment the line below to simulate the background color in Preview because the `activityBackgroundTint` can only displayed on the device or simulator.
|
||||
//.background(.black.opacity(0.85))
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
struct TrackRecordingLiveActivityWidget_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
Group {
|
||||
let activityAttributes = TrackRecordingLiveActivityAttributes()
|
||||
let activityState = TrackRecordingLiveActivityAttributes.ContentState(
|
||||
duration: .init(
|
||||
key: "Duration",
|
||||
value: "1h 12min"
|
||||
),
|
||||
distance: .init(
|
||||
key: "Distance",
|
||||
value: "12 km"
|
||||
),
|
||||
ascent: .init(
|
||||
key: "Ascent",
|
||||
value: "100 m"
|
||||
),
|
||||
descent: .init(
|
||||
key: "Descent",
|
||||
value: "100 m"
|
||||
),
|
||||
maxElevation: .init(
|
||||
key: "Max Elevation",
|
||||
value: "100 m"
|
||||
),
|
||||
minElevation: .init(
|
||||
key: "Min Elevation",
|
||||
value: "10 m"
|
||||
)
|
||||
)
|
||||
|
||||
activityAttributes
|
||||
.previewContext(activityState, viewKind: .content)
|
||||
.previewDisplayName("Notification")
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
Loading…
Add table
Add a link
Reference in a new issue