Rebrand entire project from Feels to Reflect

Complete rename across all bundle IDs, App Groups, CloudKit containers,
StoreKit product IDs, data store filenames, URL schemes, logger subsystems,
Swift identifiers, user-facing strings (7 languages), file names, directory
names, Xcode project, schemes, assets, and documentation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Trey t
2026-02-26 11:47:16 -06:00
parent b1a54d2844
commit 0442eab1f8
380 changed files with 858 additions and 1077 deletions

View File

@@ -0,0 +1,232 @@
//
// ReflectComplication.swift
// Reflect Watch App
//
// WidgetKit complications for Apple Watch.
//
import WidgetKit
import SwiftUI
// MARK: - Timeline Provider
struct ReflectTimelineProvider: TimelineProvider {
func placeholder(in context: Context) -> ReflectEntry {
ReflectEntry(date: Date(), mood: nil, streak: 0)
}
func getSnapshot(in context: Context, completion: @escaping (ReflectEntry) -> Void) {
Task { @MainActor in
let entry = createEntry()
completion(entry)
}
}
func getTimeline(in context: Context, completion: @escaping (Timeline<ReflectEntry>) -> Void) {
Task { @MainActor in
let entry = createEntry()
// Refresh at midnight for the next day
let tomorrow = Calendar.current.startOfDay(
for: Calendar.current.date(byAdding: .day, value: 1, to: Date())!
)
let timeline = Timeline(entries: [entry], policy: .after(tomorrow))
completion(timeline)
}
}
@MainActor
private func createEntry() -> ReflectEntry {
let todayEntry = ExtensionDataProvider.shared.getTodayEntry()
let streak = ExtensionDataProvider.shared.getCurrentStreak()
return ReflectEntry(
date: Date(),
mood: todayEntry?.mood,
streak: streak
)
}
}
// MARK: - Timeline Entry
struct ReflectEntry: TimelineEntry {
let date: Date
let mood: Mood?
let streak: Int
}
// MARK: - Complication Views
struct ReflectComplicationEntryView: View {
var entry: ReflectEntry
@Environment(\.widgetFamily) var family
var body: some View {
switch family {
case .accessoryCircular:
CircularView(entry: entry)
case .accessoryCorner:
CornerView(entry: entry)
case .accessoryInline:
InlineView(entry: entry)
case .accessoryRectangular:
RectangularView(entry: entry)
default:
CircularView(entry: entry)
}
}
}
// MARK: - Circular Complication
struct CircularView: View {
let entry: ReflectEntry
var body: some View {
ZStack {
AccessoryWidgetBackground()
if let mood = entry.mood {
Text(mood.watchEmoji)
.font(.system(size: 24))
} else {
VStack(spacing: 0) {
Image(systemName: "face.smiling")
.font(.system(size: 18))
Text("Log")
.font(.system(size: 10))
}
}
}
}
}
// MARK: - Corner Complication
struct CornerView: View {
let entry: ReflectEntry
var body: some View {
if let mood = entry.mood {
Text(mood.watchEmoji)
.font(.system(size: 20))
.widgetLabel {
Text(mood.widgetDisplayName)
}
} else {
Image(systemName: "face.smiling")
.font(.system(size: 20))
.widgetLabel {
Text("Log mood")
}
}
}
}
// MARK: - Inline Complication
struct InlineView: View {
let entry: ReflectEntry
var body: some View {
if entry.streak > 0 {
Label("\(entry.streak) day streak", systemImage: "flame.fill")
} else if let mood = entry.mood {
Text("\(mood.watchEmoji) \(mood.widgetDisplayName)")
} else {
Label("Log your mood", systemImage: "face.smiling")
}
}
}
// MARK: - Rectangular Complication
struct RectangularView: View {
let entry: ReflectEntry
var body: some View {
HStack {
if let mood = entry.mood {
Text(mood.watchEmoji)
.font(.system(size: 28))
VStack(alignment: .leading, spacing: 2) {
Text("Today")
.font(.system(size: 12))
.foregroundColor(.secondary)
Text(mood.widgetDisplayName)
.font(.system(size: 14, weight: .semibold))
if entry.streak > 1 {
Label("\(entry.streak) days", systemImage: "flame.fill")
.font(.system(size: 10))
.foregroundColor(.orange)
}
}
} else {
Image(systemName: "face.smiling")
.font(.system(size: 24))
VStack(alignment: .leading, spacing: 2) {
Text("Reflect")
.font(.system(size: 14, weight: .semibold))
Text("Tap to log mood")
.font(.system(size: 12))
.foregroundColor(.secondary)
}
}
Spacer()
}
}
}
// MARK: - Widget Configuration
struct ReflectComplication: Widget {
let kind: String = "ReflectComplication"
var body: some WidgetConfiguration {
StaticConfiguration(kind: kind, provider: ReflectTimelineProvider()) { entry in
ReflectComplicationEntryView(entry: entry)
.containerBackground(.fill.tertiary, for: .widget)
}
.configurationDisplayName("Reflect")
.description("See today's mood and streak.")
.supportedFamilies([
.accessoryCircular,
.accessoryCorner,
.accessoryInline,
.accessoryRectangular
])
}
}
// MARK: - Preview
#Preview("Circular - Mood") {
CircularView(entry: ReflectEntry(date: Date(), mood: .great, streak: 5))
.previewContext(WidgetPreviewContext(family: .accessoryCircular))
}
#Preview("Circular - Empty") {
CircularView(entry: ReflectEntry(date: Date(), mood: nil, streak: 0))
.previewContext(WidgetPreviewContext(family: .accessoryCircular))
}
#Preview("Rectangular - Mood") {
RectangularView(entry: ReflectEntry(date: Date(), mood: .good, streak: 7))
.previewContext(WidgetPreviewContext(family: .accessoryRectangular))
}
#Preview("Inline - Streak") {
InlineView(entry: ReflectEntry(date: Date(), mood: .great, streak: 5))
.previewContext(WidgetPreviewContext(family: .accessoryInline))
}
#Preview("Corner - Mood") {
CornerView(entry: ReflectEntry(date: Date(), mood: .average, streak: 3))
.previewContext(WidgetPreviewContext(family: .accessoryCorner))
}