Skip to content

Commit 054dcc4

Browse files
committed
Tweak real-time suggestion indicator animation
1 parent 61fbc73 commit 054dcc4

2 files changed

Lines changed: 45 additions & 14 deletions

File tree

Core/Sources/Service/GUI/RealtimeSuggestionIndicatorController.swift

Lines changed: 41 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import XPCShared
1212
final class RealtimeSuggestionIndicatorController {
1313
class IndicatorContentViewModel: ObservableObject {
1414
@Published var isPrefetching = false
15+
@Published var progress: Double = 1
1516
private var prefetchTask: Task<Void, Error>?
1617

1718
@MainActor
@@ -21,33 +22,55 @@ final class RealtimeSuggestionIndicatorController {
2122
isPrefetching = true
2223
}
2324
prefetchTask = Task {
24-
try await Task.sleep(nanoseconds: 2 * 1_000_000_000)
25-
withAnimation(.easeOut(duration: 0.2)) {
26-
isPrefetching = false
25+
try await Task.sleep(nanoseconds: 5 * 1_000_000_000)
26+
if isPrefetching {
27+
endPrefetch()
2728
}
2829
}
2930
}
31+
32+
@MainActor
33+
func endPrefetch() {
34+
withAnimation(.easeOut(duration: 0.2)) {
35+
isPrefetching = false
36+
progress = 1
37+
}
38+
}
3039
}
3140

3241
struct IndicatorContentView: View {
3342
@ObservedObject var viewModel: IndicatorContentViewModel
34-
@State var progress: CGFloat = 1
35-
var opacityA: CGFloat { min(progress, 0.7) }
36-
var opacityB: CGFloat { 1 - progress }
37-
var scaleA: CGFloat { progress / 2 + 0.5 }
38-
var scaleB: CGFloat { max(1 - progress, 0.01) }
43+
var opacityA: CGFloat { min(viewModel.progress, 0.7) }
44+
var opacityB: CGFloat { 1 - viewModel.progress }
45+
var scaleA: CGFloat { viewModel.progress / 2 + 0.5 }
46+
var scaleB: CGFloat { max(1 - viewModel.progress, 0.01) }
3947

4048
var body: some View {
4149
Circle()
4250
.fill(Color.accentColor.opacity(opacityA))
4351
.scaleEffect(.init(width: scaleA, height: scaleA))
4452
.frame(width: 8, height: 8)
45-
.background(
46-
Circle()
47-
.fill(Color.white.opacity(viewModel.isPrefetching ? opacityB : 0))
48-
.scaleEffect(.init(width: scaleB, height: scaleB))
49-
.frame(width: 8, height: 8)
50-
)
53+
.overlay {
54+
if viewModel.isPrefetching {
55+
Circle()
56+
.fill(Color.white.opacity(opacityB))
57+
.scaleEffect(.init(width: scaleB, height: scaleB))
58+
.frame(width: 8, height: 8)
59+
.onAppear {
60+
Task {
61+
await Task.yield()
62+
withAnimation(
63+
.easeInOut(duration: 0.4)
64+
.repeatForever(
65+
autoreverses: true
66+
)
67+
) {
68+
viewModel.progress = 0
69+
}
70+
}
71+
}
72+
}
73+
}
5174
}
5275
}
5376

@@ -208,4 +231,8 @@ final class RealtimeSuggestionIndicatorController {
208231
func triggerPrefetchAnimation() {
209232
viewModel.prefetch()
210233
}
234+
235+
func endPrefetchAnimation() {
236+
viewModel.endPrefetch()
237+
}
211238
}

Core/Sources/Service/SuggestionCommandHandler/CommentBaseCommandHandler.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,10 @@ struct CommentBaseCommandHandler: SuggestionCommandHanlder {
134134
guard filespace.suggestionSourceSnapshot == snapshot else { return nil }
135135

136136
let presenter = PresentInCommentSuggestionPresenter()
137+
138+
await GraphicalUserInterfaceController.shared.realtimeSuggestionIndicatorController
139+
.endPrefetchAnimation()
140+
137141
return try await presenter.presentSuggestion(
138142
for: filespace,
139143
in: workspace,

0 commit comments

Comments
 (0)