Generate labels from workout

This commit is contained in:
Christoph Hagen
2025-08-22 00:01:51 +02:00
parent 9ec207014c
commit f972a2c020
8 changed files with 108 additions and 14 deletions

View File

@@ -298,6 +298,18 @@ final class FileResource: Item, LocalizedItem {
return content.settings.general.url + version.outputPath
}
// MARK: Workout
var routeOverview: RouteOverview? {
guard type == .route else {
return nil
}
guard let data = dataContent() else {
return nil
}
return try? WorkoutData(data: data).overview
}
// MARK: Video thumbnail
func createVideoThumbnail() {

View File

@@ -77,6 +77,45 @@ final class LocalizedPost: ChangeObservingItem {
var hasVideos: Bool {
images.contains { $0.type.isVideo }
}
func updateLabels(from workout: RouteOverview, locale: Locale) {
insertOrReplace(label: .init(icon: .statisticsDistance, value: String(format: "%.1f km", locale: locale, workout.distance / 1000)))
insertOrReplace(label: .init(icon: .statisticsTime, value: workout.duration.duration(locale: locale)))
insertOrReplace(label: .init(icon: .statisticsElevationUp, value: workout.ascendedElevation.length(roundingToNearest: 50)))
insertOrReplace(label: .init(icon: .statisticsEnergy, value: workout.energy.energy(roundingToNearest: 50)))
}
func insertOrReplace(label: ContentLabel) {
if let index = labels.firstIndex(where: { $0.icon == label.icon }) {
labels[index] = label
} else {
labels.append(label)
}
}
}
private extension TimeInterval {
func duration(locale: Locale) -> String {
let totalMinutes = Int((self / 60).rounded(to: 5))
let hours = totalMinutes / 60
let minutes = totalMinutes % 60
let suffix = locale.identifier.hasPrefix("de") ? "Std" : "h"
return String(format: "%d:%02d ", hours, minutes) + suffix
}
func length(roundingToNearest interval: Double) -> String {
let rounded = Int(self.rounded(to: interval))
return "\(rounded) m"
}
func energy(roundingToNearest interval: Double) -> String {
let rounded = Int(self.rounded(to: interval))
return "\(rounded) kcal"
}
}
// MARK: Storage

View File

@@ -38,6 +38,10 @@ final class Post: Item, DateItem, LocalizedItem {
@Published
var linkedPage: Page?
/// The workout associated with the post
@Published
var associatedWorkout: FileResource?
init(content: Content,
id: String,
isDraft: Bool,
@@ -47,7 +51,8 @@ final class Post: Item, DateItem, LocalizedItem {
tags: [Tag],
german: LocalizedPost,
english: LocalizedPost,
linkedPage: Page? = nil) {
linkedPage: Page? = nil,
associatedWorkout: FileResource? = nil) {
self.isDraft = isDraft
self.createdDate = createdDate
self.startDate = startDate
@@ -57,6 +62,7 @@ final class Post: Item, DateItem, LocalizedItem {
self.german = german
self.english = english
self.linkedPage = linkedPage
self.associatedWorkout = associatedWorkout
super.init(content: content, id: id)
}
@@ -174,6 +180,14 @@ final class Post: Item, DateItem, LocalizedItem {
english: english,
tags: tags)
}
func updateLabelsFromWorkout() {
guard let overview = associatedWorkout?.routeOverview else {
return
}
german.updateLabels(from: overview, locale: Locale(identifier: "de_DE"))
english.updateLabels(from: overview, locale: Locale(identifier: "en_US"))
}
}
extension Post: StorageItem {
@@ -189,7 +203,8 @@ extension Post: StorageItem {
tags: data.tags.compactMap(context.tag),
german: .init(context: context, data: data.german),
english: .init(context: context, data: data.english),
linkedPage: data.linkedPageId.map(context.page))
linkedPage: data.linkedPageId.map(context.page),
associatedWorkout: data.associatedWorkoutId.map(context.file))
savedData = data
}
@@ -202,6 +217,7 @@ extension Post: StorageItem {
let german: LocalizedPost.Data
let english: LocalizedPost.Data
let linkedPageId: String?
let associatedWorkoutId: String?
}
var data: Data {
@@ -213,7 +229,8 @@ extension Post: StorageItem {
tags: tags.map { $0.identifier },
german: german.data,
english: english.data,
linkedPageId: linkedPage?.identifier)
linkedPageId: linkedPage?.identifier,
associatedWorkoutId: associatedWorkout?.identifier)
}
func saveToDisk(_ data: Data) -> Bool {