Files
mindfulness/client/ios/情绪小组件/EmotionWidget.swift
2026-01-28 23:41:03 +08:00

205 lines
6.7 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 WidgetKit
import SwiftUI
// V1Small/Medium/Large + Home
struct EmotionProvider: TimelineProvider {
func placeholder(in context: Context) -> EmotionEntry {
EmotionEntry(date: Date())
}
func getSnapshot(in context: Context, completion: @escaping (EmotionEntry) -> ()) {
completion(EmotionEntry(date: Date()))
}
func getTimeline(in context: Context, completion: @escaping (Timeline<EmotionEntry>) -> ()) {
// V1
let entry = EmotionEntry(date: Date())
let nextUpdate = Calendar.current.date(byAdding: .day, value: 7, to: Date())
?? Date().addingTimeInterval(60 * 60 * 24 * 7)
completion(Timeline(entries: [entry], policy: .after(nextUpdate)))
}
}
struct EmotionEntry: TimelineEntry {
let date: Date
}
struct EmotionWidgetView: View {
var entry: EmotionProvider.Entry
@Environment(\.widgetFamily) var family
private let title = "正念"
private let text = "你已经很努力了,今天也值得被温柔对待。"
private let deepLink = URL(string: "client:///(app)/home")
var body: some View {
switch family {
case .systemSmall:
smallView()
case .systemMedium:
mediumView()
case .systemLarge:
largeView()
default:
smallView()
}
}
// iOS 15
private func cardBackground(colors: [Color]) -> some View {
ZStack {
LinearGradient(
colors: colors,
startPoint: .topLeading,
endPoint: .bottomTrailing
)
//
RadialGradient(
gradient: Gradient(colors: [Color.white.opacity(0.16), Color.white.opacity(0.0)]),
center: .topTrailing,
startRadius: 10,
endRadius: 180
)
}
.overlay(
RoundedRectangle(cornerRadius: 18, style: .continuous)
.stroke(Color.white.opacity(0.14), lineWidth: 1)
)
.cornerRadius(18)
}
private func chip(_ text: String) -> some View {
Text(text)
.font(.system(size: 12, weight: .semibold))
.foregroundColor(Color.white.opacity(0.9))
.padding(.horizontal, 10)
.padding(.vertical, 6)
.background(Color.white.opacity(0.14))
.cornerRadius(999)
}
private func smallView() -> some View {
ZStack {
cardBackground(colors: [
Color(red: 0.06, green: 0.08, blue: 0.12),
Color(red: 0.13, green: 0.16, blue: 0.22),
])
VStack(alignment: .leading, spacing: 10) {
HStack {
chip(title)
Spacer(minLength: 0)
}
Text(text)
.font(.system(size: 15, weight: .semibold))
.foregroundColor(Color.white.opacity(0.92))
.lineSpacing(2)
.lineLimit(4)
Spacer(minLength: 0)
Text("点我回到 App")
.font(.system(size: 11, weight: .medium))
.foregroundColor(Color.white.opacity(0.65))
}
.padding(14)
}
.widgetURL(deepLink)
}
private func mediumView() -> some View {
ZStack {
cardBackground(colors: [
Color(red: 0.06, green: 0.08, blue: 0.12),
Color(red: 0.09, green: 0.11, blue: 0.17),
])
HStack(alignment: .top, spacing: 14) {
VStack(alignment: .leading, spacing: 10) {
chip(title)
Text(text)
.font(.system(size: 17, weight: .semibold))
.foregroundColor(Color.white.opacity(0.92))
.lineSpacing(3)
.lineLimit(5)
Spacer(minLength: 0)
Text("轻轻呼吸,回到当下")
.font(.system(size: 12, weight: .medium))
.foregroundColor(Color.white.opacity(0.7))
}
//
VStack(alignment: .trailing, spacing: 8) {
Text(entry.date, style: .time)
.font(.system(size: 12, weight: .semibold))
.foregroundColor(Color.white.opacity(0.8))
Spacer(minLength: 0)
Text("今日")
.font(.system(size: 28, weight: .bold))
.foregroundColor(Color.white.opacity(0.12))
}
}
.padding(16)
}
.widgetURL(deepLink)
}
private func largeView() -> some View {
ZStack {
cardBackground(colors: [
Color(red: 0.06, green: 0.08, blue: 0.12),
Color(red: 0.14, green: 0.18, blue: 0.28),
])
VStack(alignment: .leading, spacing: 14) {
HStack {
chip(title)
Spacer(minLength: 0)
Text(entry.date, style: .time)
.font(.system(size: 12, weight: .semibold))
.foregroundColor(Color.white.opacity(0.78))
}
Text(text)
.font(.system(size: 20, weight: .semibold))
.foregroundColor(Color.white.opacity(0.92))
.lineSpacing(4)
.lineLimit(8)
Spacer(minLength: 0)
HStack {
Text("点我回到 Home")
.font(.system(size: 12, weight: .medium))
.foregroundColor(Color.white.opacity(0.7))
Spacer(minLength: 0)
Text("🌿")
.font(.system(size: 18))
.opacity(0.9)
}
}
.padding(18)
}
.widgetURL(deepLink)
}
}
@main
struct EmotionWidget: Widget {
let kind: String = "EmotionWidget"
var body: some WidgetConfiguration {
StaticConfiguration(kind: kind, provider: EmotionProvider()) { entry in
EmotionWidgetView(entry: entry)
}
.configurationDisplayName("情绪小组件")
.description("一段温柔提醒,陪你回到当下。")
.supportedFamilies([.systemSmall, .systemMedium, .systemLarge])
}
}