Fix memory leaks and add debug tools, remove ControlCenterTip

Memory optimization:
- Add onDisappear cleanup for repeatForever animations in LockScreenView
- Add onDisappear cleanup for animations in FeelsSubscriptionStoreView
- Add onDisappear cleanup in AddMoodHeaderView and PaywallPreviewSettingsView

Debug improvements:
- Add test data and clear data buttons to Settings (debug builds only)

TipKit changes:
- Remove ControlCenterTip (unused)
- Add TipKit-Tips.md documentation

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Trey t
2025-12-28 21:07:22 -06:00
parent c4e013763a
commit e98142c72e
9 changed files with 370 additions and 60 deletions

View File

@@ -382,6 +382,9 @@ struct OrbitVotingView: View {
centerPulse = 1.1
}
}
.onDisappear {
centerPulse = 1.0
}
.accessibilityElement(children: .contain)
.accessibilityLabel(String(localized: "Mood selection"))
}
@@ -589,6 +592,9 @@ struct NeonVotingView: View {
pulsePhase = true
}
}
.onDisappear {
pulsePhase = false
}
}
private var neonGridBackground: some View {

View File

@@ -151,6 +151,10 @@ struct CelestialMarketingContent: View {
showContent = true
}
}
.onDisappear {
animateGradient = false
animateOrbs = false
}
}
}
@@ -221,6 +225,10 @@ struct GardenMarketingContent: View {
showContent = true
}
}
.onDisappear {
bloomPhase = false
swayPhase = false
}
}
}
@@ -299,6 +307,11 @@ struct NeonMarketingContent: View {
showContent = true
}
}
.onDisappear {
pulsePhase = false
glowPhase = false
scanlineOffset = 0
}
}
}
@@ -358,6 +371,9 @@ struct MinimalMarketingContent: View {
showContent = true
}
}
.onDisappear {
breathe = false
}
}
}
@@ -415,6 +431,9 @@ struct ZenMarketingContent: View {
showContent = true
}
}
.onDisappear {
inkFlow = false
}
}
}
@@ -548,6 +567,9 @@ struct MixtapeMarketingContent: View {
showContent = true
}
}
.onDisappear {
tapeRotation = false
}
}
}
@@ -612,6 +634,9 @@ struct HeartfeltMarketingContent: View {
showContent = true
}
}
.onDisappear {
heartbeat = false
}
}
}
@@ -674,6 +699,9 @@ struct LuxeMarketingContent: View {
showContent = true
}
}
.onDisappear {
shimmer = false
}
}
}
@@ -738,6 +766,9 @@ struct ForecastMarketingContent: View {
showContent = true
}
}
.onDisappear {
cloudDrift = false
}
}
}
@@ -802,6 +833,9 @@ struct PlayfulMarketingContent: View {
showContent = true
}
}
.onDisappear {
bounce = false
}
}
}
@@ -858,6 +892,9 @@ struct JournalMarketingContent: View {
showContent = true
}
}
.onDisappear {
pageFlip = false
}
}
}
@@ -1452,6 +1489,9 @@ struct EmotionOrb: View {
pulse = true
}
}
.onDisappear {
pulse = false
}
}
}

View File

@@ -118,22 +118,6 @@ struct AuroraBackground: View {
.blur(radius: 40)
.offset(y: animateGradient ? -10 : 10)
// Noise texture overlay
Rectangle()
.fill((isDark ? Color.white : Color.black).opacity(0.015))
.background(
Canvas { context, size in
for _ in 0..<1000 {
let x = CGFloat.random(in: 0...size.width)
let y = CGFloat.random(in: 0...size.height)
let opacity = Double.random(in: 0.01...0.04)
context.fill(
Path(ellipseIn: CGRect(x: x, y: y, width: 1, height: 1)),
with: .color((isDark ? Color.white : Color.black).opacity(opacity))
)
}
}
)
}
.ignoresSafeArea()
.onAppear {
@@ -365,6 +349,9 @@ struct ZenLockBackground: View {
breathe = true
}
}
.onDisappear {
breathe = false
}
}
}
@@ -401,6 +388,9 @@ struct ZenEnsoOrb: View {
breathe = true
}
}
.onDisappear {
breathe = false
}
}
}
@@ -450,6 +440,9 @@ struct NeonLockBackground: View {
pulse = true
}
}
.onDisappear {
pulse = false
}
}
}
@@ -501,6 +494,10 @@ struct NeonRingOrb: View {
pulse = true
}
}
.onDisappear {
rotate = false
pulse = false
}
}
}
@@ -560,6 +557,9 @@ struct CelestialLockBackground: View {
twinkle = true
}
}
.onDisappear {
twinkle = false
}
}
}
@@ -620,6 +620,10 @@ struct CelestialOrbsElement: View {
float = true
}
}
.onDisappear {
rotate = false
float = false
}
}
}
@@ -704,21 +708,6 @@ struct MixtapeLockBackground: View {
endPoint: shift ? .bottomTrailing : .bottomLeading
)
// Noise texture
Rectangle()
.fill(.white.opacity(0.03))
.background(
Canvas { context, size in
for _ in 0..<500 {
let x = CGFloat.random(in: 0...size.width)
let y = CGFloat.random(in: 0...size.height)
context.fill(
Path(ellipseIn: CGRect(x: x, y: y, width: 1, height: 1)),
with: .color(.white.opacity(Double.random(in: 0.02...0.06)))
)
}
}
)
}
.ignoresSafeArea()
.onAppear {
@@ -726,6 +715,9 @@ struct MixtapeLockBackground: View {
shift = true
}
}
.onDisappear {
shift = false
}
}
}
@@ -775,6 +767,9 @@ struct CassetteElement: View {
spin = true
}
}
.onDisappear {
spin = false
}
}
}
@@ -818,6 +813,9 @@ struct BloomLockBackground: View {
bloom = true
}
}
.onDisappear {
bloom = false
}
}
}
@@ -867,6 +865,9 @@ struct FlowerElement: View {
bloom = true
}
}
.onDisappear {
bloom = false
}
}
}
@@ -904,6 +905,9 @@ struct HeartfeltLockBackground: View {
pulse = true
}
}
.onDisappear {
pulse = false
}
}
}
@@ -940,6 +944,9 @@ struct HeartElement: View {
beat = true
}
}
.onDisappear {
beat = false
}
}
}
@@ -1000,6 +1007,9 @@ struct MinimalCircleElement: View {
breathe = true
}
}
.onDisappear {
breathe = false
}
}
}
@@ -1037,6 +1047,9 @@ struct LuxeLockBackground: View {
shimmer = true
}
}
.onDisappear {
shimmer = false
}
}
}
@@ -1078,6 +1091,10 @@ struct DiamondElement: View {
shimmer = true
}
}
.onDisappear {
rotate = false
shimmer = false
}
}
}
@@ -1117,6 +1134,9 @@ struct ForecastLockBackground: View {
drift = true
}
}
.onDisappear {
drift = false
}
}
}
@@ -1169,6 +1189,9 @@ struct WeatherElement: View {
shine = true
}
}
.onDisappear {
shine = false
}
}
}
@@ -1235,6 +1258,10 @@ struct PlayfulEmojiElement: View {
bounce = true
}
}
.onDisappear {
wiggle = false
bounce = false
}
}
}
@@ -1326,6 +1353,9 @@ struct JournalBookElement: View {
open = true
}
}
.onDisappear {
open = false
}
}
}
@@ -1863,6 +1893,9 @@ struct NeonUnlockButton: View {
pulse = true
}
}
.onDisappear {
pulse = false
}
}
}

View File

@@ -386,6 +386,9 @@ struct CelestialMiniPreview: View {
animate = true
}
}
.onDisappear {
animate = false
}
}
private var orbColors: [Color] {
@@ -445,6 +448,9 @@ struct GardenMiniPreview: View {
bloom = true
}
}
.onDisappear {
bloom = false
}
}
}
@@ -508,6 +514,9 @@ struct NeonMiniPreview: View {
pulse = true
}
}
.onDisappear {
pulse = false
}
}
}
@@ -552,6 +561,9 @@ struct MinimalMiniPreview: View {
breathe = true
}
}
.onDisappear {
breathe = false
}
}
}
@@ -592,6 +604,9 @@ struct ZenMiniPreview: View {
breathe = true
}
}
.onDisappear {
breathe = false
}
}
}
@@ -668,6 +683,9 @@ struct MixtapeMiniPreview: View {
spin = true
}
}
.onDisappear {
spin = false
}
}
}
@@ -710,6 +728,9 @@ struct HeartfeltMiniPreview: View {
beat = true
}
}
.onDisappear {
beat = false
}
}
}
@@ -756,6 +777,9 @@ struct LuxeMiniPreview: View {
shimmer = true
}
}
.onDisappear {
shimmer = false
}
}
}
@@ -801,6 +825,9 @@ struct ForecastMiniPreview: View {
drift = true
}
}
.onDisappear {
drift = false
}
}
}
@@ -847,6 +874,9 @@ struct PlayfulMiniPreview: View {
bounce = true
}
}
.onDisappear {
bounce = false
}
}
}

View File

@@ -55,6 +55,8 @@ struct SettingsContentView: View {
trialDateButton
animationLabButton
paywallPreviewButton
addTestDataButton
clearDataButton
#endif
Spacer()
@@ -159,7 +161,6 @@ struct SettingsContentView: View {
}
.padding(.top, 20)
.padding(.horizontal, 4)
.controlCenterTip()
}
private var legalSectionHeader: some View {
@@ -331,6 +332,66 @@ struct SettingsContentView: View {
}
}
}
private var addTestDataButton: some View {
ZStack {
theme.currentTheme.secondaryBGColor
Button {
DataController.shared.populateTestData()
} label: {
HStack(spacing: 12) {
Image(systemName: "plus.square.on.square")
.font(.title2)
.foregroundColor(.green)
.frame(width: 32)
VStack(alignment: .leading, spacing: 2) {
Text("Add Test Data")
.foregroundColor(textColor)
Text("Populate with sample mood entries")
.font(.caption)
.foregroundStyle(.secondary)
}
Spacer()
}
.padding()
}
}
.fixedSize(horizontal: false, vertical: true)
.cornerRadius(Constants.viewsCornerRaidus, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
}
private var clearDataButton: some View {
ZStack {
theme.currentTheme.secondaryBGColor
Button {
DataController.shared.clearDB()
} label: {
HStack(spacing: 12) {
Image(systemName: "trash")
.font(.title2)
.foregroundColor(.red)
.frame(width: 32)
VStack(alignment: .leading, spacing: 2) {
Text("Clear All Data")
.foregroundColor(textColor)
Text("Delete all mood entries")
.font(.caption)
.foregroundStyle(.secondary)
}
Spacer()
}
.padding()
}
}
.fixedSize(horizontal: false, vertical: true)
.cornerRadius(Constants.viewsCornerRaidus, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
}
#endif
// MARK: - Privacy Lock Toggle