From 4b739dd194b1f38573c5bc0f2c3c614ca3608ad5 Mon Sep 17 00:00:00 2001
From: 1 <1>
Date: Mon, 2 Feb 2026 17:17:10 +0800
Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=8C=E5=96=84=E5=90=AF=E5=8A=A8?=
=?UTF-8?q?=E5=88=86=E5=8F=91=E9=80=BB=E8=BE=91=EF=BC=8C=E4=BC=98=E5=8C=96?=
=?UTF-8?q?=E5=B0=8F=E7=BB=84=E4=BB=B6=E8=83=8C=E6=99=AF=E9=80=82=E9=85=8D?=
=?UTF-8?q?=E4=B8=8E=E7=82=B9=E8=B5=9E=E5=9B=BE=E6=A0=87=E4=BA=A4=E4=BA=92?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
client/app.json | 8 +-
client/app/(onboarding)/onboarding.tsx | 3 +-
client/app/index.tsx | 16 +-
client/assets/images/home/like_filled.svg | 2 +-
client/assets/images/icon/like_icon.svg | 2 +-
client/ios/情绪小组件/EmotionWidget.swift | 227 +++++++++++++++-------
6 files changed, 179 insertions(+), 79 deletions(-)
diff --git a/client/app.json b/client/app.json
index 00ddbaf..6c4afd0 100644
--- a/client/app.json
+++ b/client/app.json
@@ -1,11 +1,11 @@
{
"expo": {
- "name": "Hey Mama",
- "slug": "hey-mama",
+ "name": "client",
+ "slug": "client",
"version": "1.0.0",
"orientation": "portrait",
"icon": "./assets/images/icon.png",
- "scheme": "heymama",
+ "scheme": "client",
"userInterfaceStyle": "automatic",
"newArchEnabled": true,
"splash": {
@@ -15,7 +15,7 @@
},
"ios": {
"supportsTablet": true,
- "bundleIdentifier": "com.heymama.app"
+ "bundleIdentifier": "com.anonymous.client"
},
"android": {
"adaptiveIcon": {
diff --git a/client/app/(onboarding)/onboarding.tsx b/client/app/(onboarding)/onboarding.tsx
index df0ef33..929ce6e 100644
--- a/client/app/(onboarding)/onboarding.tsx
+++ b/client/app/(onboarding)/onboarding.tsx
@@ -97,7 +97,8 @@ export default function OnboardingScreen() {
}
};
- const onSkip = () => {
+ const onSkip = async () => {
+ await setOnboardingCompleted(true);
router.replace('/(app)/home');
};
diff --git a/client/app/index.tsx b/client/app/index.tsx
index e9a5ae3..64ba2ad 100644
--- a/client/app/index.tsx
+++ b/client/app/index.tsx
@@ -14,9 +14,9 @@ export default function Index() {
useEffect(() => {
let cancelled = false;
(async () => {
- // 【完全重置】:清除本地存储的所有数据(收藏、设置、引导状态等)
+ // 【临时清除数据】:用于测试完整流程
await AsyncStorage.clear();
- console.log('AsyncStorage has been cleared.');
+ console.log('AsyncStorage has been cleared for testing.');
// 1. 检查是否同意协议
const consentAccepted = await getConsentAccepted();
@@ -27,9 +27,17 @@ export default function Index() {
return;
}
- // 2. 检查 Onboarding
+ // 2. 检查 Onboarding 是否已完成
const completed = await getOnboardingCompleted();
- router.replace(completed ? '/(app)/home' : '/(onboarding)/onboarding');
+ if (cancelled) return;
+
+ if (completed) {
+ // 如果已经完成过流程,直接进 Home
+ router.replace('/(app)/home');
+ } else {
+ // 如果是首次进入(或未完成流程),进入 Onboarding
+ router.replace('/(onboarding)/onboarding');
+ }
})();
return () => {
cancelled = true;
diff --git a/client/assets/images/home/like_filled.svg b/client/assets/images/home/like_filled.svg
index cb3c2c1..f8749df 100644
--- a/client/assets/images/home/like_filled.svg
+++ b/client/assets/images/home/like_filled.svg
@@ -1,4 +1,4 @@
diff --git a/client/assets/images/icon/like_icon.svg b/client/assets/images/icon/like_icon.svg
index bd94d57..a52fe32 100644
--- a/client/assets/images/icon/like_icon.svg
+++ b/client/assets/images/icon/like_icon.svg
@@ -1,3 +1,3 @@
diff --git a/client/ios/情绪小组件/EmotionWidget.swift b/client/ios/情绪小组件/EmotionWidget.swift
index 510cc41..3376cfa 100644
--- a/client/ios/情绪小组件/EmotionWidget.swift
+++ b/client/ios/情绪小组件/EmotionWidget.swift
@@ -1,54 +1,28 @@
import WidgetKit
import SwiftUI
-// V2:纯色背景 + 随机文案小组件(Small/Medium/Large + 点击跳转 Home)
+// V1:写死文案的小组件(Small/Medium/Large + 点击跳转 Home)
struct EmotionProvider: TimelineProvider {
- private let quotes = [
- "你已经很努力了,今天也值得被温柔对待。",
- "轻轻呼吸,感受当下的每一刻。",
- "所有的压力,都会在深呼吸中慢慢消散。",
- "给生活一点留白,给自己一点温柔。",
- "不要走得太快,等一等落下的灵魂。",
- "世界虽嘈杂,但你可以拥有一颗宁静的心。",
- "每一个瞬间,都是生命最好的安排。",
- "抱抱自己,辛苦了,亲爱的。",
- "慢一点也没关系,只要你在前行。",
- "今天,你对自己微笑了吗?",
- "愿你历经山河,仍觉得人间值得。",
- "心简单,世界就简单;心平顺,生活就平顺。",
- "即使生活偶尔晦暗,你也要成为自己的光。",
- "别让琐事挤走生活的快乐,别让压力消磨奋斗的激情。"
- ]
-
func placeholder(in context: Context) -> EmotionEntry {
- EmotionEntry(date: Date(), text: quotes[0])
+ EmotionEntry(date: Date())
}
func getSnapshot(in context: Context, completion: @escaping (EmotionEntry) -> ()) {
- let entry = EmotionEntry(date: Date(), text: quotes.randomElement() ?? quotes[0])
- completion(entry)
+ completion(EmotionEntry(date: Date()))
}
func getTimeline(in context: Context, completion: @escaping (Timeline) -> ()) {
- var entries: [EmotionEntry] = []
- let currentDate = Date()
-
- // 生成未来 24 小时的 6 个条目,每 4 小时更换一次随机文案
- for hourOffset in 0..<6 {
- let entryDate = Calendar.current.date(byAdding: .hour, value: hourOffset * 4, to: currentDate)!
- let entry = EmotionEntry(date: entryDate, text: quotes.randomElement() ?? quotes[0])
- entries.append(entry)
- }
-
- let timeline = Timeline(entries: entries, policy: .atEnd)
- completion(timeline)
+ // 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
- let text: String
}
struct EmotionWidgetView: View {
@@ -56,37 +30,160 @@ struct EmotionWidgetView: View {
@Environment(\.widgetFamily) var family
private let title = "正念"
+ private let text = "你已经很努力了,今天也值得被温柔对待。"
private let deepLink = URL(string: "client:///(app)/home")
-
- // 背景色 #F7D9BF
- private let backgroundColor = Color(red: 247/255, green: 217/255, blue: 191/255)
- // 文本颜色(深咖色,适合搭配浅橘色背景)
- private let textColor = Color(red: 74/255, green: 52/255, blue: 40/255)
var body: some View {
- VStack(alignment: .center, spacing: 0) {
- Spacer(minLength: 0)
-
- Text(entry.text)
- .font(.system(size: family == .systemSmall ? 17 : 20, weight: .medium))
- .foregroundColor(textColor)
- .lineSpacing(6)
- .multilineTextAlignment(.center)
- .minimumScaleFactor(0.7)
- .fixedSize(horizontal: false, vertical: true)
-
- Spacer(minLength: 0)
-
- if family != .systemSmall {
- Text("Hey Mama")
- .font(.system(size: 10, weight: .semibold))
- .foregroundColor(textColor.opacity(0.3))
- .padding(.bottom, 4)
- }
+ 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)
}
- .padding(family == .systemSmall ? 16 : 24)
- .frame(maxWidth: .infinity, maxHeight: .infinity) // 强制撑开容器
- .background(backgroundColor) // 将背景色直接应用到容器上
.widgetURL(deepLink)
}
}
@@ -97,13 +194,7 @@ struct EmotionWidget: Widget {
var body: some WidgetConfiguration {
StaticConfiguration(kind: kind, provider: EmotionProvider()) { entry in
- if #available(iOS 17.0, *) {
- EmotionWidgetView(entry: entry)
- .containerBackground(Color(red: 247/255, green: 217/255, blue: 191/255), for: .widget)
- } else {
- EmotionWidgetView(entry: entry)
- .background(Color(red: 247/255, green: 217/255, blue: 191/255))
- }
+ EmotionWidgetView(entry: entry)
}
.configurationDisplayName("情绪小组件")
.description("一段温柔提醒,陪你回到当下。")