// // ExportableWatchViews.swift // Reflect // // Exportable watch views that match the real watchOS layouts. // These views accept tint/icon configuration as parameters for batch export. // import SwiftUI // MARK: - Watch Export Configuration /// Configuration for watch view export styling struct WatchExportConfig { let moodTint: MoodTintable.Type let moodImages: MoodImagable.Type /// Get emoji for a mood based on the image style func emoji(for mood: Mood) -> String { // Map MoodImagable type to WatchMoodImageStyle equivalent switch String(describing: moodImages) { case "FontAwesomeMoodImages": return fontAwesomeEmoji(for: mood) case "EmojiMoodImages": return emojiStyle(for: mood) case "HandEmojiMoodImages": return handEmoji(for: mood) case "WeatherMoodImages": return weatherEmoji(for: mood) case "GardenMoodImages": return gardenEmoji(for: mood) case "HeartsMoodImages": return heartsEmoji(for: mood) case "CosmicMoodImages": return cosmicEmoji(for: mood) default: return emojiStyle(for: mood) } } private func fontAwesomeEmoji(for mood: Mood) -> String { switch mood { case .great: return "😁" case .good: return "🙂" case .average: return "😐" case .bad: return "🙁" case .horrible: return "😫" case .missing, .placeholder: return "❓" } } private func emojiStyle(for mood: Mood) -> String { switch mood { case .great: return "😀" case .good: return "🙂" case .average: return "😑" case .bad: return "😕" case .horrible: return "💩" case .missing, .placeholder: return "❓" } } private func handEmoji(for mood: Mood) -> String { switch mood { case .great: return "🙏" case .good: return "👍" case .average: return "🖖" case .bad: return "👎" case .horrible: return "🖕" case .missing, .placeholder: return "❓" } } private func weatherEmoji(for mood: Mood) -> String { switch mood { case .great: return "☀️" case .good: return "⛅" case .average: return "☁️" case .bad: return "🌧️" case .horrible: return "⛈️" case .missing: return "🌫️" case .placeholder: return "❓" } } private func gardenEmoji(for mood: Mood) -> String { switch mood { case .great: return "🌸" case .good: return "🌿" case .average: return "🌱" case .bad: return "🍂" case .horrible: return "🥀" case .missing: return "🕳️" case .placeholder: return "❓" } } private func heartsEmoji(for mood: Mood) -> String { switch mood { case .great: return "💖" case .good: return "🩷" case .average: return "🤍" case .bad: return "🩶" case .horrible: return "💔" case .missing: return "🖤" case .placeholder: return "❓" } } private func cosmicEmoji(for mood: Mood) -> String { switch mood { case .great: return "⭐" case .good: return "🌕" case .average: return "🌓" case .bad: return "🌑" case .horrible: return "🕳️" case .missing: return "✧" case .placeholder: return "❓" } } } // MARK: - Exportable Watch Voting View /// Watch voting interface - matches ContentView from watch app struct ExportableWatchVotingView: View { let config: WatchExportConfig var body: some View { VStack(spacing: 8) { Text("How do you feel?") .font(.system(size: 16, weight: .medium)) .foregroundColor(.secondary) // Top row: Great, Good, Average HStack(spacing: 8) { ExportableWatchMoodButton(mood: .great, config: config) ExportableWatchMoodButton(mood: .good, config: config) ExportableWatchMoodButton(mood: .average, config: config) } // Bottom row: Bad, Horrible HStack(spacing: 8) { ExportableWatchMoodButton(mood: .bad, config: config) ExportableWatchMoodButton(mood: .horrible, config: config) } } } } // MARK: - Exportable Watch Mood Button struct ExportableWatchMoodButton: View { let mood: Mood let config: WatchExportConfig var body: some View { Text(config.emoji(for: mood)) .font(.system(size: 28)) .frame(maxWidth: .infinity) .frame(height: 50) .background(config.moodTint.color(forMood: mood).opacity(0.3)) .cornerRadius(12) } } // MARK: - Exportable Watch Already Rated View struct ExportableWatchAlreadyRatedView: View { let mood: Mood let config: WatchExportConfig var body: some View { VStack(spacing: 12) { Text(config.emoji(for: mood)) .font(.system(size: 50)) Text("Logged!") .font(.system(size: 18, weight: .semibold)) .foregroundColor(.secondary) } } } // MARK: - Exportable Circular Complication struct ExportableCircularComplication: View { let mood: Mood? let config: WatchExportConfig var body: some View { ZStack { Circle() .fill(Color(white: 0.15)) if let mood = mood { Text(config.emoji(for: mood)) .font(.system(size: 24)) } else { VStack(spacing: 0) { Image(systemName: "face.smiling") .font(.system(size: 18)) Text("Log") .font(.system(size: 10)) } } } } } // MARK: - Exportable Corner Complication struct ExportableCornerComplication: View { let mood: Mood? let config: WatchExportConfig var body: some View { HStack(spacing: 4) { if let mood = mood { Text(config.emoji(for: mood)) .font(.system(size: 20)) Text(mood.widgetDisplayName) .font(.system(size: 12)) .foregroundColor(.secondary) } else { Image(systemName: "face.smiling") .font(.system(size: 20)) Text("Log mood") .font(.system(size: 12)) .foregroundColor(.secondary) } } } } // MARK: - Exportable Inline Complication struct ExportableInlineComplication: View { let mood: Mood? let streak: Int let config: WatchExportConfig var body: some View { HStack(spacing: 4) { if streak > 0 { Image(systemName: "flame.fill") .foregroundColor(.orange) Text("\(streak) day streak") } else if let mood = mood { Text("\(config.emoji(for: mood)) \(mood.widgetDisplayName)") } else { Image(systemName: "face.smiling") Text("Log your mood") } } .font(.system(size: 14)) } } // MARK: - Exportable Rectangular Complication struct ExportableRectangularComplication: View { let mood: Mood? let streak: Int let config: WatchExportConfig var body: some View { HStack { if let mood = mood { Text(config.emoji(for: mood)) .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 streak > 1 { HStack(spacing: 2) { Image(systemName: "flame.fill") Text("\(streak) days") } .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: - Watch Container for Export struct ExportableWatchContainer: View { let width: CGFloat let height: CGFloat let colorScheme: ColorScheme let cornerRadius: CGFloat let content: Content init(width: CGFloat, height: CGFloat, colorScheme: ColorScheme, cornerRadius: CGFloat = 20, @ViewBuilder content: () -> Content) { self.width = width self.height = height self.colorScheme = colorScheme self.cornerRadius = cornerRadius self.content = content() } private var backgroundColor: Color { colorScheme == .dark ? Color.black : Color(red: 0.95, green: 0.95, blue: 0.97) } var body: some View { content .environment(\.colorScheme, colorScheme) .frame(width: width, height: height) .background(backgroundColor) .clipShape(RoundedRectangle(cornerRadius: cornerRadius, style: .continuous)) } } // MARK: - Watch Complication Container struct ExportableComplicationContainer: View { let size: CGSize let colorScheme: ColorScheme let isCircular: Bool let content: Content init(size: CGSize, colorScheme: ColorScheme, isCircular: Bool = false, @ViewBuilder content: () -> Content) { self.size = size self.colorScheme = colorScheme self.isCircular = isCircular self.content = content() } private var backgroundColor: Color { colorScheme == .dark ? Color(white: 0.1) : Color(white: 0.95) } var body: some View { content .environment(\.colorScheme, colorScheme) .frame(width: size.width, height: size.height) .background(backgroundColor) .clipShape(isCircular ? AnyShape(Circle()) : AnyShape(RoundedRectangle(cornerRadius: 12, style: .continuous))) } }