moodlit-native/Widgets/MoodlitWidget/SmallMoodsView.swift
till 03dca7d84d μ-7.3: Widget (Small/Medium/Large) + Deep-Link-Handling
WidgetSnapshot-Bridge App ↔ Widget via App-Group-UserDefaults
(`group.ev.mana.moodlit`). MoodStore.refreshWidgetSnapshot läuft
nach loadAll + toggleFavorite und pingt WidgetCenter.

Widget-Extension (`ev.mana.moodlit.widget`, iOS-only app-extension):
- Small: Last-Played oder erstes Favorit als Glow-Tile + Name +
  Animation-Slug
- Medium: 2×2-Grid, bis zu 4 Favoriten, jede Kachel hat eigene
  Link-Destination zum App-Player
- Large: 3×3-Grid, bis zu 9 Favoriten + Footer mit Total-Count
- Empty-State, wenn keine Favoriten gesetzt sind

Deep-Links:
- `moodlit://play/<id>` (Custom-Scheme aus Widget-Tap):
  `url.host == "play"`, ID aus pathComponents
- `https://moodlit.mana.how/play/<id>` (Universal-Link via AASA):
  pathComponents == ["/", "play", "<id>"]
Beide öffnen MoodPlayerView als fullScreenCover direkt auf RootView
(unabhängig vom aktiven Tab).

Wegen Widget-Target-Sharing: `Mood.swiftUIColors` aus HexColor.swift
nach Mood+SwiftUI.swift extrahiert (Widget kennt den Mood-Type nicht).

xcodebuild iOS-Sim + macOS beide BUILD SUCCEEDED. Widget-Extension
korrekt eingebettet in `MoodlitNative.app/PlugIns/`. 11 Unit-Tests
weiter grün.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 15:21:55 +02:00

63 lines
1.5 KiB
Swift

import SwiftUI
import WidgetKit
/// Small-Widget zeigt das zuletzt gespielte Mood (Fallback: erstes
/// Favorit) als Glow-Tile mit Namen + Animation-Slug.
struct SmallMoodsView: View {
let entry: MoodsEntry
private var displayMood: WidgetMood? {
entry.snapshot?.lastPlayed ?? entry.snapshot?.favorites.first
}
var body: some View {
if let mood = displayMood {
content(mood)
} else {
emptyState
}
}
private func content(_ mood: WidgetMood) -> some View {
ZStack(alignment: .bottomLeading) {
LinearGradient(
colors: mood.colors.map { Color(hex: $0) },
startPoint: .topLeading,
endPoint: .bottomTrailing
)
.ignoresSafeArea()
LinearGradient(
colors: [.black.opacity(0.55), .clear],
startPoint: .bottom,
endPoint: .center
)
VStack(alignment: .leading, spacing: 4) {
Text(mood.name)
.font(.headline)
.foregroundStyle(.white)
.shadow(radius: 4)
Text(mood.animation.capitalized)
.font(.caption2.weight(.medium))
.foregroundStyle(.white.opacity(0.85))
}
.padding(8)
}
.widgetURL(URL(string: "moodlit://play/\(mood.id)"))
}
private var emptyState: some View {
VStack(spacing: 6) {
Image(systemName: "sparkles")
.font(.title2)
.foregroundStyle(.white.opacity(0.7))
Text("Keine Favoriten")
.font(.caption)
.foregroundStyle(.white.opacity(0.7))
Text("Markiere ein Mood als Favorit")
.font(.caption2)
.foregroundStyle(.white.opacity(0.5))
.multilineTextAlignment(.center)
}
.padding(8)
}
}