moodlit-native/Widgets/MoodlitWidget/LargeMoodsView.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

81 lines
1.8 KiB
Swift
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import SwiftUI
import WidgetKit
/// Large-Widget bis zu 9 Favoriten als 3×3-Grid + Total-Count im
/// Footer. Tap auf Kachel öffnet App im Player.
struct LargeMoodsView: View {
let entry: MoodsEntry
private var moods: [WidgetMood] {
Array((entry.snapshot?.favorites ?? []).prefix(9))
}
private var totalCount: Int {
entry.snapshot?.favorites.count ?? 0
}
var body: some View {
if moods.isEmpty {
MediumMoodsView(entry: entry) // Reuse empty state
} else {
content
}
}
private var content: some View {
VStack(spacing: 6) {
LazyVGrid(
columns: Array(repeating: GridItem(.flexible(), spacing: 6), count: 3),
spacing: 6
) {
ForEach(moods) { mood in
Link(destination: URL(string: "moodlit://play/\(mood.id)")!) {
tile(mood)
}
}
}
footer
}
.padding(6)
}
private func tile(_ mood: WidgetMood) -> some View {
ZStack(alignment: .bottomLeading) {
LinearGradient(
colors: mood.colors.map { Color(hex: $0) },
startPoint: .topLeading,
endPoint: .bottomTrailing
)
LinearGradient(
colors: [.black.opacity(0.55), .clear],
startPoint: .bottom,
endPoint: .center
)
Text(mood.name)
.font(.caption2.weight(.semibold))
.foregroundStyle(.white)
.shadow(radius: 3)
.lineLimit(1)
.padding(.horizontal, 6)
.padding(.bottom, 4)
}
.clipShape(RoundedRectangle(cornerRadius: 6, style: .continuous))
.aspectRatio(1, contentMode: .fit)
}
private var footer: some View {
HStack {
Image(systemName: "heart.fill")
.font(.caption2)
.foregroundStyle(.red.opacity(0.85))
Text("\(totalCount) Favoriten")
.font(.caption2)
.foregroundStyle(.white.opacity(0.7))
Spacer()
Text("Moodlit")
.font(.caption2.weight(.medium))
.foregroundStyle(.white.opacity(0.85))
}
.padding(.horizontal, 6)
}
}