feat: fix travel placement bug, add theme-based alternate icons, fix animated background crash

- Fix repeat-city travel placement: use stop indices instead of global city name
  matching so Follow Team trips with repeat cities show travel correctly
- Add TravelPlacement helper and regression tests (7 tests)
- Add alternate app icons for each theme, auto-switch on theme change
- Fix index-out-of-range crash in AnimatedSportsBackground (19 configs, was iterating 20)
- Add marketing video configs, engine, and new video components
- Add docs and data exports

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Trey t
2026-02-06 09:36:34 -06:00
parent fdcecafaa3
commit 8e937a5646
77 changed files with 143400 additions and 83 deletions

View File

@@ -34,6 +34,19 @@ enum AppTheme: String, CaseIterable, Identifiable {
}
}
/// The alternate icon name in the asset catalog, or nil for the default (teal).
var alternateIconName: String? {
switch self {
case .teal: return nil
case .orbit: return "AppIcon-orbit"
case .retro: return "AppIcon-retro"
case .clutch: return "AppIcon-clutch"
case .monochrome: return "AppIcon-monochrome"
case .sunset: return "AppIcon-sunset"
case .midnight: return "AppIcon-midnight"
}
}
var previewColors: [Color] {
switch self {
case .teal: return [Color(hex: "4ECDC4"), Color(hex: "1A535C"), Color(hex: "FFE66D")]
@@ -56,9 +69,16 @@ final class ThemeManager {
var currentTheme: AppTheme {
didSet {
UserDefaults.standard.set(currentTheme.rawValue, forKey: "selectedTheme")
updateAppIcon(for: currentTheme)
}
}
private func updateAppIcon(for theme: AppTheme) {
let iconName = theme.alternateIconName
guard UIApplication.shared.alternateIconName != iconName else { return }
UIApplication.shared.setAlternateIconName(iconName)
}
private init() {
if let saved = UserDefaults.standard.string(forKey: "selectedTheme"),
let theme = AppTheme(rawValue: saved) {