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>
63 lines
1.5 KiB
Swift
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)
|
|
}
|
|
}
|