Skip to content

Commit 18a5b34

Browse files
committed
Adjust implementation of chat panel
1 parent 7dc23dc commit 18a5b34

File tree

1 file changed

+52
-48
lines changed

1 file changed

+52
-48
lines changed

Core/Sources/ChatGPTChatTab/ChatPanel.swift

Lines changed: 52 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -66,19 +66,16 @@ struct ChatPanelMessages: View {
6666
}
6767

6868
Spacer(minLength: 12)
69-
.onAppear {
70-
withAnimation {
71-
proxy.scrollTo(bottomID, anchor: .bottom)
72-
}
73-
}
7469
.id(bottomID)
70+
.task {
71+
proxy.scrollTo(bottomID, anchor: .bottom)
72+
}
7573
.background(GeometryReader { geo in
7674
let offset = geo.frame(in: .named(scrollSpace)).minY
77-
Color.clear
78-
.preference(
79-
key: ScrollViewOffsetPreferenceKey.self,
80-
value: offset
81-
)
75+
Color.clear.preference(
76+
key: ScrollViewOffsetPreferenceKey.self,
77+
value: offset
78+
)
8279
})
8380
.preference(
8481
key: ListHeightPreferenceKey.self,
@@ -96,12 +93,16 @@ struct ChatPanelMessages: View {
9693
.listStyle(.plain)
9794
.coordinateSpace(name: scrollSpace)
9895
.onPreferenceChange(ListHeightPreferenceKey.self) { value in
99-
listHeight = value
100-
updatePinningState()
96+
Task { @MainActor in
97+
listHeight = value
98+
updatePinningState()
99+
}
101100
}
102101
.onPreferenceChange(ScrollViewOffsetPreferenceKey.self) { value in
103-
scrollOffset = value
104-
updatePinningState()
102+
Task { @MainActor in
103+
scrollOffset = value
104+
updatePinningState()
105+
}
105106
}
106107
.overlay(alignment: .bottom) {
107108
WithViewStore(chat, observe: \.isReceivingMessage) { viewStore in
@@ -114,51 +115,54 @@ struct ChatPanelMessages: View {
114115
}
115116
}
116117
.overlay(alignment: .bottomTrailing) {
117-
WithViewStore(chat, observe: \.history.last) { viewStore in
118-
Button(action: {
119-
withAnimation(.easeInOut(duration: 0.1)) {
120-
proxy.scrollTo(bottomID, anchor: .bottom)
121-
}
122-
}) {
123-
Image(systemName: "arrow.down")
124-
.padding(4)
125-
.background {
126-
Circle()
127-
.fill(.thickMaterial)
128-
.shadow(color: .black.opacity(0.2), radius: 2)
129-
}
130-
.overlay {
131-
Circle().stroke(Color(nsColor: .separatorColor), lineWidth: 1)
132-
}
133-
.foregroundStyle(.secondary)
134-
.padding(4)
135-
}
136-
.keyboardShortcut(.downArrow, modifiers: [.command])
137-
.opacity(pinnedToBottom ? 0 : 1)
138-
.buttonStyle(.plain)
139-
.onChange(of: viewStore.state) { _ in
140-
if pinnedToBottom || isInitialLoad {
141-
if isInitialLoad {
142-
isInitialLoad = false
143-
}
144-
withAnimation {
145-
proxy.scrollTo(bottomID, anchor: .bottom)
146-
}
147-
}
148-
}
149-
}
118+
scrollToBottomButton(proxy: proxy)
150119
}
151120
}
152121
}
153122
}
154123

155124
func updatePinningState() {
156-
if scrollOffset > listHeight + 24 + 100 || scrollOffset <= 0 {
125+
if scrollOffset > listHeight + 30 + 100 || scrollOffset <= 0 {
157126
pinnedToBottom = false
158127
} else {
159128
pinnedToBottom = true
160129
}
161130
}
131+
132+
@ViewBuilder
133+
func scrollToBottomButton(proxy: ScrollViewProxy) -> some View {
134+
WithViewStore(chat, observe: \.history.last) { viewStore in
135+
Button(action: {
136+
withAnimation(.easeInOut(duration: 0.1)) {
137+
proxy.scrollTo(bottomID, anchor: .bottom)
138+
}
139+
}) {
140+
Image(systemName: "arrow.down")
141+
.padding(4)
142+
.background {
143+
Circle()
144+
.fill(.thickMaterial)
145+
.shadow(color: .black.opacity(0.2), radius: 2)
146+
}
147+
.overlay {
148+
Circle().stroke(Color(nsColor: .separatorColor), lineWidth: 1)
149+
}
150+
.foregroundStyle(.secondary)
151+
.padding(4)
152+
}
153+
.keyboardShortcut(.downArrow, modifiers: [.command])
154+
.opacity(pinnedToBottom ? 0 : 1)
155+
.buttonStyle(.plain)
156+
.onChange(of: viewStore.state) { _ in
157+
if pinnedToBottom || isInitialLoad {
158+
if isInitialLoad {
159+
isInitialLoad = false
160+
}
161+
proxy.scrollTo(bottomID, anchor: .bottom)
162+
}
163+
}
164+
}
165+
}
162166
}
163167

164168
struct ChatHistory: View {

0 commit comments

Comments
 (0)