205 lines
6.7 KiB
Swift
205 lines
6.7 KiB
Swift
import WidgetKit
|
||
import SwiftUI
|
||
|
||
// V1:写死文案的小组件(Small/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])
|
||
}
|
||
}
|
||
|