Files
Reflect/Shared/Views/SharingTemplates/Variations/LongestStreakVariations.swift
Trey t bfef0a4472 Add sharing style picker for design variation selection
Users can now swipe between design variations (e.g. Gradient vs Color Block)
when sharing from month/year views and the sharing templates list. Removes
#if DEBUG wrappers from variation files and disables auto-start demo animation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 09:26:21 -06:00

240 lines
9.0 KiB
Swift

//
// LongestStreakVariations.swift
// Feels
//
// 2 design variations for the Longest Streak sharing template.
//
import SwiftUI
// MARK: - V2 "Gradient Bar" Warm gradient bg, horizontal progress
struct LongestStreakV2: View {
let streakEntries: [MoodEntryModel]
let selectedMood: Mood
@AppStorage(UserDefaultsStore.Keys.moodTint.rawValue, store: GroupUserDefaults.groupDefaults)
private var moodTint: MoodTints = .Default
private let dateFormatter: DateFormatter = {
let f = DateFormatter()
f.dateFormat = "MMM d, yyyy"
return f
}()
var image: UIImage {
shareView.asImage(size: CGSize(width: 650, height: 400))
}
var shareView: some View {
ZStack {
LinearGradient(
colors: [Color(hex: "FFF5EE"), Color(hex: "FFE4D6")],
startPoint: .topLeading,
endPoint: .bottomTrailing
)
VStack(spacing: 20) {
// Top row
HStack {
VStack(alignment: .leading, spacing: 4) {
Text("Longest Streak")
.font(.system(size: 14, weight: .semibold, design: .rounded))
.foregroundColor(Color(hex: "8B5E3C"))
.textCase(.uppercase)
.tracking(2)
HStack(alignment: .firstTextBaseline, spacing: 8) {
Text("\(streakEntries.count)")
.font(.system(size: 56, weight: .heavy, design: .rounded))
.foregroundColor(Color(hex: "4A2810"))
Text("days")
.font(.system(size: 20, weight: .medium, design: .rounded))
.foregroundColor(Color(hex: "8B5E3C"))
}
}
Spacer()
ZStack {
Circle()
.fill(moodTint.color(forMood: selectedMood))
.frame(width: 72, height: 72)
.shadow(color: moodTint.color(forMood: selectedMood).opacity(0.4), radius: 12)
selectedMood.icon
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 32, height: 32)
.foregroundColor(.white)
}
}
.padding(.horizontal, 36)
// Progress bar
VStack(spacing: 8) {
GeometryReader { geo in
ZStack(alignment: .leading) {
Capsule()
.fill(Color(hex: "4A2810").opacity(0.1))
.frame(height: 24)
Capsule()
.fill(moodTint.color(forMood: selectedMood))
.frame(width: geo.size.width * 0.85, height: 24)
.shadow(color: moodTint.color(forMood: selectedMood).opacity(0.3), radius: 6)
}
}
.frame(height: 24)
HStack {
Text(dateFormatter.string(from: streakEntries.first?.forDate ?? Date()))
.font(.system(size: 12, weight: .medium, design: .rounded))
.foregroundColor(Color(hex: "8B5E3C").opacity(0.6))
Spacer()
Text(dateFormatter.string(from: streakEntries.last?.forDate ?? Date()))
.font(.system(size: 12, weight: .medium, design: .rounded))
.foregroundColor(Color(hex: "8B5E3C").opacity(0.6))
}
}
.padding(.horizontal, 36)
// Footer
HStack {
Text(selectedMood.strValue)
.font(.system(size: 14, weight: .semibold, design: .rounded))
.foregroundColor(Color(hex: "8B5E3C"))
Spacer()
VStack(spacing: 6) {
Image("FeelsAppIcon")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 72, height: 72)
.clipShape(RoundedRectangle(cornerRadius: 16))
Text("Feels")
.font(.system(size: 22, weight: .medium, design: .rounded))
.foregroundColor(Color(hex: "8B5E3C").opacity(0.4))
}
}
.padding(.horizontal, 36)
}
.padding(.vertical, 32)
}
.frame(width: 650, height: 400)
}
var body: some View { shareView }
}
// MARK: - V3 "Dark Badge" Dark bg, glowing badge, neon accent
struct LongestStreakV3: View {
let streakEntries: [MoodEntryModel]
let selectedMood: Mood
@AppStorage(UserDefaultsStore.Keys.moodTint.rawValue, store: GroupUserDefaults.groupDefaults)
private var moodTint: MoodTints = .Default
private let dateFormatter: DateFormatter = {
let f = DateFormatter()
f.dateStyle = .medium
return f
}()
var image: UIImage {
shareView.asImage(size: CGSize(width: 650, height: 400))
}
var shareView: some View {
ZStack {
Color(hex: "0A0A0F")
HStack(spacing: 0) {
// Left half badge centered
ZStack {
Circle()
.fill(moodTint.color(forMood: selectedMood).opacity(0.15))
.frame(width: 220, height: 220)
Circle()
.stroke(moodTint.color(forMood: selectedMood).opacity(0.3), lineWidth: 2)
.frame(width: 180, height: 180)
Circle()
.stroke(moodTint.color(forMood: selectedMood), lineWidth: 3)
.frame(width: 150, height: 150)
VStack(spacing: 4) {
Text("\(streakEntries.count)")
.font(.system(size: 60, weight: .heavy, design: .rounded))
.foregroundColor(.white)
Text("DAYS")
.font(.system(size: 13, weight: .bold))
.foregroundColor(moodTint.color(forMood: selectedMood))
.tracking(4)
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
// Right half text left-aligned, vertically centered
VStack(alignment: .leading, spacing: 20) {
Text("LONGEST STREAK")
.font(.system(size: 14, weight: .bold))
.foregroundColor(Color(hex: "6E6E80"))
.tracking(4)
HStack(spacing: 10) {
selectedMood.icon
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 28, height: 28)
.foregroundColor(moodTint.color(forMood: selectedMood))
Text(selectedMood.strValue)
.font(.system(size: 30, weight: .semibold))
.foregroundColor(.white)
}
VStack(alignment: .leading, spacing: 6) {
Text(dateFormatter.string(from: streakEntries.first?.forDate ?? Date()))
.font(.system(size: 18, weight: .medium))
.foregroundColor(.white.opacity(0.7))
Text("")
.font(.system(size: 16))
.foregroundColor(Color(hex: "6E6E80"))
Text(dateFormatter.string(from: streakEntries.last?.forDate ?? Date()))
.font(.system(size: 18, weight: .medium))
.foregroundColor(.white.opacity(0.7))
}
VStack(spacing: 6) {
Image("FeelsAppIcon")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 72, height: 72)
.clipShape(RoundedRectangle(cornerRadius: 16))
Text("Feels")
.font(.system(size: 22, weight: .medium))
.foregroundColor(Color(hex: "3A3A4A"))
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.padding(.leading, 20)
}
}
.frame(width: 650, height: 400)
}
var body: some View { shareView }
}