464fbb2bad
App de watchOS de solo consulta: resumen de cartera (total, cambio del mes y mayores posiciones), objetivos con su progreso y estado del check-in con la racha. Toda la edición sigue en el iPhone. Complicaciones (accessoryCircular / Rectangular / Inline / Corner): valor total de la cartera, progreso del objetivo más cercano a cumplirse y racha + estado del check-in. Datos: los App Groups no se comparten entre iOS y watchOS, así que el reloj no puede leer el store de CoreData que lee el widget de iOS. En su lugar, WatchSyncService construye un WatchPortfolioSnapshot ligero y lo envía como application context de WatchConnectivity, enganchado a CoreDataStack.refreshWidgetData() — el mismo punto que refresca el widget de iOS, así que cualquier repositorio que toque datos refresca el reloj. WatchDataStore lo cachea en el App Group del watch (WatchSnapshotCache) y recarga las timelines; la extensión de complicaciones solo lee ese caché. Proyecto: dos targets nuevos (watchOS app + widget extension) con grupos sincronizados de Xcode 16; Shared/ pertenece a la app de watch y se comparte con la app de iOS y el widget mediante exception sets, el mismo mecanismo que ya usaba el widget de iOS para el modelo de CoreData. Scheme compartido PortfolioJournalWatch. Localización propia por target en los 7 idiomas. Verificado: compilan los tres targets, la app de watch queda embebida en Watch/ con la extensión en PlugIns/, y en el par de simuladores iPhone 17 Pro Max + Apple Watch Series 11 el reloj recibe y muestra el snapshot enviado por el iPhone. 10 tests nuevos del payload. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YcDn5ccuRFV83q7xWWokBT
19 lines
717 B
Swift
19 lines
717 B
Swift
import SwiftUI
|
|
|
|
extension Color {
|
|
/// Parses the `#RRGGBB` strings categories are stored with. Kept separate
|
|
/// from the iOS `Color(hex:)` helper so the watch targets stay free of the
|
|
/// rest of the app's utilities.
|
|
init?(watchHex hex: String?) {
|
|
guard let hex else { return nil }
|
|
var value = hex.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
if value.hasPrefix("#") { value.removeFirst() }
|
|
guard value.count == 6, let rgb = UInt32(value, radix: 16) else { return nil }
|
|
self.init(
|
|
red: Double((rgb & 0xFF0000) >> 16) / 255,
|
|
green: Double((rgb & 0x00FF00) >> 8) / 255,
|
|
blue: Double(rgb & 0x0000FF) / 255
|
|
)
|
|
}
|
|
}
|