Skip to content

Commit 5bfe0a6

Browse files
committed
Adjust animation
1 parent ad8f6ec commit 5bfe0a6

File tree

1 file changed

+24
-47
lines changed

1 file changed

+24
-47
lines changed

Core/Sources/SuggestionWidget/WidgetView.swift

Lines changed: 24 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ struct WidgetView: View {
4242
value: isHovering
4343
)
4444
.animation(
45-
.easeInOut(duration: 0.2),
45+
.easeInOut(duration: 0.4),
4646
value: store.isProcessing
4747
)
4848
}
@@ -54,11 +54,9 @@ struct WidgetAnimatedCapsule: View {
5454
let store: StoreOf<CircularWidget>
5555
var isHovering: Bool
5656

57-
@State private var animatedProgress: CGFloat = 0 // 0~1
57+
@State private var breathingOpacity: CGFloat = 1.0
5858
@State private var animationTask: Task<Void, Never>?
5959

60-
private let movingSegmentLength: CGFloat = 0.28
61-
6260
var body: some View {
6361
GeometryReader { geo in
6462
WithPerceptionTracking {
@@ -68,6 +66,7 @@ struct WidgetAnimatedCapsule: View {
6866
let backgroundWidth = capsuleWidth
6967
let foregroundWidth = max(capsuleWidth - 4, 2)
7068
let padding = (backgroundWidth - foregroundWidth) / 2
69+
let foregroundHeight = capsuleHeight - padding * 2
7170

7271
ZStack {
7372
Capsule()
@@ -91,87 +90,65 @@ struct WidgetAnimatedCapsule: View {
9190
}
9291
}
9392
.frame(width: backgroundWidth, height: capsuleHeight)
94-
.animation(.easeInOut(duration: 0.14), value: isHovering)
9593

9694
Capsule()
97-
.fill(Color.accentColor.opacity(0.8))
95+
.fill(Color.white)
9896
.frame(
9997
width: foregroundWidth,
100-
height: capsuleHeight * movingSegmentLength
101-
)
102-
.opacity(store.isProcessing ? 1 : 0)
103-
.position(
104-
x: capsuleWidth / 2,
105-
y: {
106-
let height = capsuleHeight - padding * 2
107-
let base = padding
108-
return base + height * (normalizedStart() + movingSegmentLength / 2)
109-
}()
98+
height: foregroundHeight
11099
)
111-
.animation(nil, value: store.isProcessing)
112-
.animation(.easeInOut(duration: 0.14), value: isHovering)
100+
.opacity({
101+
let base = store.isProcessing ? breathingOpacity : 0
102+
if isHovering {
103+
return min(base + 0.5, 1.0)
104+
}
105+
return base
106+
}())
107+
.blur(radius: 2)
113108
}
114109
.onAppear {
115-
updateAnimationTask(isProcessing: store.isProcessing)
110+
updateBreathingAnimation(isProcessing: store.isProcessing)
116111
}
117112
.onChange(of: store.isProcessing) { newValue in
118-
updateAnimationTask(isProcessing: newValue)
119-
}
120-
.onChange(of: store.isContentEmpty) { _ in
121-
if !store.isProcessing {
122-
animatedProgress = store.isContentEmpty ? 0 : 1
123-
}
113+
updateBreathingAnimation(isProcessing: newValue)
124114
}
125-
.onChange(of: isHovering) { _ in }
126115
}
127116
}
128117
}
129118

130-
// 进度条起点
131-
private func normalizedStart() -> CGFloat {
132-
let p = max(0, min(1, animatedProgress))
133-
return p * (1 - movingSegmentLength)
134-
}
135-
136-
// 动画任务
137-
private func updateAnimationTask(isProcessing: Bool) {
119+
private func updateBreathingAnimation(isProcessing: Bool) {
138120
animationTask?.cancel()
139121
animationTask = nil
140122

141123
if isProcessing {
142-
animationTask = Task { [weak store] in
143-
await MainActor.run {
144-
animatedProgress = 0
145-
}
124+
animationTask = Task {
146125
while !Task.isCancelled {
147126
await MainActor.run {
148-
withAnimation(.linear(duration: 1.2)) {
149-
animatedProgress = 1
127+
withAnimation(.easeInOut(duration: 1.2)) {
128+
breathingOpacity = 0.3
150129
}
151130
}
152131
try? await Task.sleep(nanoseconds: UInt64(1.2 * 1_000_000_000))
153132
if Task.isCancelled { break }
154-
if !(store?.isProcessing ?? true) { break }
133+
if !(store.isProcessing) { break }
155134
await MainActor.run {
156-
withAnimation(.linear(duration: 1.2)) {
157-
animatedProgress = 0
135+
withAnimation(.easeInOut(duration: 1.2)) {
136+
breathingOpacity = 1.0
158137
}
159138
}
160139
try? await Task.sleep(nanoseconds: UInt64(1.2 * 1_000_000_000))
161140
if Task.isCancelled { break }
162-
if !(store?.isProcessing ?? true) { break }
141+
if !(store.isProcessing) { break }
163142
}
164143
}
165144
} else {
166145
withAnimation(.easeInOut(duration: 0.2)) {
167-
animatedProgress = store.isContentEmpty ? 0 : 1
146+
breathingOpacity = 0
168147
}
169148
}
170149
}
171150
}
172151

173-
// 下面的WidgetContextMenu和其它内容保持不变喵~
174-
175152
struct WidgetContextMenu: View {
176153
@AppStorage(\.useGlobalChat) var useGlobalChat
177154
@AppStorage(\.realtimeSuggestionToggle) var realtimeSuggestionToggle

0 commit comments

Comments
 (0)