Merge branch 'custom_ish'

This commit is contained in:
Trey t
2026-01-16 15:38:28 -06:00
18 changed files with 3393 additions and 65 deletions

View File

@@ -20,6 +20,7 @@ enum CKRecordType {
static let stadiumAlias = "StadiumAlias"
static let tripPoll = "TripPoll"
static let pollVote = "PollVote"
static let customItineraryItem = "CustomItineraryItem"
}
// MARK: - CKTeam
@@ -622,3 +623,74 @@ struct CKPollVote {
)
}
}
// MARK: - CKCustomItineraryItem
struct CKCustomItineraryItem {
static let itemIdKey = "itemId"
static let tripIdKey = "tripId"
static let categoryKey = "category"
static let titleKey = "title"
static let anchorTypeKey = "anchorType"
static let anchorIdKey = "anchorId"
static let anchorDayKey = "anchorDay"
static let sortOrderKey = "sortOrder"
static let createdAtKey = "createdAt"
static let modifiedAtKey = "modifiedAt"
let record: CKRecord
init(record: CKRecord) {
self.record = record
}
init(item: CustomItineraryItem) {
let record = CKRecord(
recordType: CKRecordType.customItineraryItem,
recordID: CKRecord.ID(recordName: item.id.uuidString)
)
record[CKCustomItineraryItem.itemIdKey] = item.id.uuidString
record[CKCustomItineraryItem.tripIdKey] = item.tripId.uuidString
record[CKCustomItineraryItem.categoryKey] = item.category.rawValue
record[CKCustomItineraryItem.titleKey] = item.title
record[CKCustomItineraryItem.anchorTypeKey] = item.anchorType.rawValue
record[CKCustomItineraryItem.anchorIdKey] = item.anchorId
record[CKCustomItineraryItem.anchorDayKey] = item.anchorDay
record[CKCustomItineraryItem.sortOrderKey] = item.sortOrder
record[CKCustomItineraryItem.createdAtKey] = item.createdAt
record[CKCustomItineraryItem.modifiedAtKey] = item.modifiedAt
self.record = record
}
func toItem() -> CustomItineraryItem? {
guard let itemIdString = record[CKCustomItineraryItem.itemIdKey] as? String,
let itemId = UUID(uuidString: itemIdString),
let tripIdString = record[CKCustomItineraryItem.tripIdKey] as? String,
let tripId = UUID(uuidString: tripIdString),
let categoryString = record[CKCustomItineraryItem.categoryKey] as? String,
let category = CustomItineraryItem.ItemCategory(rawValue: categoryString),
let title = record[CKCustomItineraryItem.titleKey] as? String,
let anchorTypeString = record[CKCustomItineraryItem.anchorTypeKey] as? String,
let anchorType = CustomItineraryItem.AnchorType(rawValue: anchorTypeString),
let anchorDay = record[CKCustomItineraryItem.anchorDayKey] as? Int,
let createdAt = record[CKCustomItineraryItem.createdAtKey] as? Date,
let modifiedAt = record[CKCustomItineraryItem.modifiedAtKey] as? Date
else { return nil }
let anchorId = record[CKCustomItineraryItem.anchorIdKey] as? String
let sortOrder = record[CKCustomItineraryItem.sortOrderKey] as? Int ?? 0
return CustomItineraryItem(
id: itemId,
tripId: tripId,
category: category,
title: title,
anchorType: anchorType,
anchorId: anchorId,
anchorDay: anchorDay,
sortOrder: sortOrder,
createdAt: createdAt,
modifiedAt: modifiedAt
)
}
}

View File

@@ -0,0 +1,83 @@
//
// CustomItineraryItem.swift
// SportsTime
//
import Foundation
struct CustomItineraryItem: Identifiable, Codable, Hashable {
let id: UUID
let tripId: UUID
var category: ItemCategory
var title: String
var anchorType: AnchorType
var anchorId: String?
var anchorDay: Int
var sortOrder: Int // For ordering within same anchor position
let createdAt: Date
var modifiedAt: Date
init(
id: UUID = UUID(),
tripId: UUID,
category: ItemCategory,
title: String,
anchorType: AnchorType = .startOfDay,
anchorId: String? = nil,
anchorDay: Int,
sortOrder: Int = 0,
createdAt: Date = Date(),
modifiedAt: Date = Date()
) {
self.id = id
self.tripId = tripId
self.category = category
self.title = title
self.anchorType = anchorType
self.anchorId = anchorId
self.anchorDay = anchorDay
self.sortOrder = sortOrder
self.createdAt = createdAt
self.modifiedAt = modifiedAt
}
enum ItemCategory: String, Codable, CaseIterable {
case restaurant
case hotel
case activity
case note
var icon: String {
switch self {
case .restaurant: return "🍽️"
case .hotel: return "🏨"
case .activity: return "🎯"
case .note: return "📝"
}
}
var label: String {
switch self {
case .restaurant: return "Restaurant"
case .hotel: return "Hotel"
case .activity: return "Activity"
case .note: return "Note"
}
}
var systemImage: String {
switch self {
case .restaurant: return "fork.knife"
case .hotel: return "bed.double.fill"
case .activity: return "figure.run"
case .note: return "note.text"
}
}
}
enum AnchorType: String, Codable {
case startOfDay
case afterGame
case afterTravel
}
}

View File

@@ -101,6 +101,79 @@ final class TripVote {
}
}
// MARK: - Local Custom Item (Cache)
@Model
final class LocalCustomItem {
@Attribute(.unique) var id: UUID
var tripId: UUID
var category: String
var title: String
var anchorType: String
var anchorId: String?
var anchorDay: Int
var createdAt: Date
var modifiedAt: Date
var pendingSync: Bool // True if needs to sync to CloudKit
init(
id: UUID = UUID(),
tripId: UUID,
category: CustomItineraryItem.ItemCategory,
title: String,
anchorType: CustomItineraryItem.AnchorType = .startOfDay,
anchorId: String? = nil,
anchorDay: Int,
createdAt: Date = Date(),
modifiedAt: Date = Date(),
pendingSync: Bool = false
) {
self.id = id
self.tripId = tripId
self.category = category.rawValue
self.title = title
self.anchorType = anchorType.rawValue
self.anchorId = anchorId
self.anchorDay = anchorDay
self.createdAt = createdAt
self.modifiedAt = modifiedAt
self.pendingSync = pendingSync
}
var toItem: CustomItineraryItem? {
guard let category = CustomItineraryItem.ItemCategory(rawValue: category),
let anchorType = CustomItineraryItem.AnchorType(rawValue: anchorType)
else { return nil }
return CustomItineraryItem(
id: id,
tripId: tripId,
category: category,
title: title,
anchorType: anchorType,
anchorId: anchorId,
anchorDay: anchorDay,
createdAt: createdAt,
modifiedAt: modifiedAt
)
}
static func from(_ item: CustomItineraryItem, pendingSync: Bool = false) -> LocalCustomItem {
LocalCustomItem(
id: item.id,
tripId: item.tripId,
category: item.category,
title: item.title,
anchorType: item.anchorType,
anchorId: item.anchorId,
anchorDay: item.anchorDay,
createdAt: item.createdAt,
modifiedAt: item.modifiedAt,
pendingSync: pendingSync
)
}
}
// MARK: - User Preferences
@Model