| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394 |
- import Foundation
- import SwiftData
- struct TimelineLocation: Hashable {
- let name: String
- let address: String
- let latitude: Double
- let longitude: Double
- var subtitle: String {
- let trimmedAddress = address.trimmingCharacters(in: .whitespacesAndNewlines)
- return trimmedAddress == name ? "" : trimmedAddress
- }
- }
- @Model
- final class CelestiaTimelineEvent {
- var id: UUID
- var relativeTimeMs: Int64
- var eventType: String // NOTE, PHOTO, MARKER, VOICE
- var textContent: String?
- var localFilePath: String?
- var voiceStartOffsetMs: Int64?
- var voiceEndOffsetMs: Int64?
- // Optional defaults keep existing SwiftData stores compatible.
- var locationName: String? = nil
- var locationAddress: String? = nil
- var latitude: Double? = nil
- var longitude: Double? = nil
- var createdAt: Date
-
- var session: CelestiaSession?
-
- var relativeTimeFormatted: String {
- let totalSeconds = Int(relativeTimeMs / 1000)
- let hours = totalSeconds / 3600
- let minutes = (totalSeconds % 3600) / 60
- let seconds = totalSeconds % 60
- if hours > 0 {
- return String(format: "%d:%02d:%02d", hours, minutes, seconds)
- }
- return String(format: "%02d:%02d", minutes, seconds)
- }
- var isContinuationMarker: Bool {
- eventType == "MARKER" && textContent?.hasPrefix("续录时间:") == true
- }
- var location: TimelineLocation? {
- get {
- guard let latitude, let longitude else { return nil }
- let fallbackName = locationAddress?
- .trimmingCharacters(in: .whitespacesAndNewlines)
- let name = locationName?
- .trimmingCharacters(in: .whitespacesAndNewlines)
- let displayName = (name?.isEmpty == false ? name : fallbackName)
- .flatMap { $0.isEmpty ? nil : $0 }
- ?? "所在位置"
- return TimelineLocation(
- name: displayName,
- address: locationAddress ?? "",
- latitude: latitude,
- longitude: longitude
- )
- }
- set {
- locationName = newValue?.name
- locationAddress = newValue?.address
- latitude = newValue?.latitude
- longitude = newValue?.longitude
- }
- }
-
- var eventIcon: String {
- if isContinuationMarker {
- return "record.circle"
- }
- switch eventType {
- case "PHOTO": return "camera.fill"
- case "NOTE": return "note.text"
- case "MARKER": return "exclamationmark.triangle.fill"
- case "VOICE": return "mic.fill"
- default: return "circle.fill"
- }
- }
-
- init(id: UUID = UUID(), relativeTimeMs: Int64, eventType: String) {
- self.id = id
- self.relativeTimeMs = relativeTimeMs
- self.eventType = eventType
- self.createdAt = Date()
- }
- }
|