Skip to content
Merged
Changes from 3 commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
e11d290
Merge tag '0.26.0' into develop
intitni Oct 22, 2023
62a6e85
Disable hit test when a chat panel tab is not active
intitni Oct 22, 2023
27ad97c
Update
intitni Oct 30, 2023
a9f3f48
Merge branch 'feature/retrieve-from-active-document' into develop
intitni Oct 30, 2023
ad9c008
Add new scope @sense
intitni Oct 30, 2023
5bdaf24
Update instruction
intitni Oct 30, 2023
ddbfece
Add settings for scopes
intitni Oct 31, 2023
3f25cc5
Adjust UI
intitni Oct 31, 2023
e1f4b54
Update UI
intitni Oct 31, 2023
2b5d950
Update to setup scope according to settings
intitni Oct 31, 2023
f528d9a
Support changing default scopes in chat panel
intitni Oct 31, 2023
956f712
Add Scope enum to represent scopes
intitni Oct 31, 2023
39b387d
Support changing model according to scopes
intitni Oct 31, 2023
d55b05c
Support persisting scopes of chat panel
intitni Oct 31, 2023
5f71a97
Update
intitni Oct 31, 2023
67a9eb0
Merge branch 'feature/search-scope' into develop
intitni Oct 31, 2023
4b34f20
Update
intitni Nov 2, 2023
403a918
Add new logger
intitni Nov 2, 2023
c03ce88
Fix tests
intitni Nov 2, 2023
4158c6b
Add ContextAwarePromptToCodeService
intitni Nov 3, 2023
f47d2d3
Update
intitni Nov 6, 2023
582bdc4
Update
intitni Nov 6, 2023
5848281
Merge branch 'feature/prompt-to-code-with-chat-context-support' into …
intitni Nov 6, 2023
4209f86
Make chat window title bar and traffic light button bigger
intitni Nov 2, 2023
e1cdd69
Merge branch 'feature/adjust-chat-window-title-bar-ui' into develop
intitni Nov 6, 2023
0167734
Update focus code finder to return more info about contexts
intitni Nov 8, 2023
8923f39
Prevent variable declaration being used as code range
intitni Nov 8, 2023
585df56
Support proService clean up
intitni Nov 8, 2023
4740bae
Add keys
intitni Nov 8, 2023
1f3650a
Reset to use old prompt to code service
intitni Nov 8, 2023
fd84744
Update
intitni Nov 8, 2023
4a39591
Add new OpenAI model
intitni Nov 8, 2023
7dc23dc
Merge branch 'feature/add-new-models' into develop
intitni Nov 8, 2023
18a5b34
Adjust implementation of chat panel
intitni Nov 9, 2023
ab97bad
Tweak pin to bottom behavior of chat panel
intitni Nov 9, 2023
4974b20
Merge branch 'feature/chat-panel-improvement' into develop
intitni Nov 9, 2023
8330640
Move context system prompt to right next to the latest message
intitni Nov 9, 2023
6938c9f
Merge branch 'feature/adjust-position-of-context-system-prompt' into …
intitni Nov 9, 2023
309c70f
Track scroll event to disable pin to bottom
intitni Nov 9, 2023
e6940a5
Merge branch 'feature/use-scroll-event-to-disable-pin-to-bottom' into…
intitni Nov 9, 2023
651d29b
Bump Github Copilot to 1.11.4
intitni Nov 9, 2023
1cf2781
Bump Codeium to 1.4.15
intitni Nov 9, 2023
93c5404
Fix a crash that calls dropLast with a negative number
intitni Nov 9, 2023
228b2b2
Update
intitni Nov 9, 2023
ee2aefb
Update
intitni Nov 9, 2023
9b0b4bc
Fix chat panel interfere
intitni Nov 9, 2023
65e603e
Select the first chat tab after restoring
intitni Nov 9, 2023
ab3be0d
Fix that prompt to code can open at launch
intitni Nov 9, 2023
78809ef
Update
intitni Nov 9, 2023
02ae983
Bump version to 0.27.0
intitni Nov 9, 2023
aac6509
Add sense scope to auto completion
intitni Nov 9, 2023
d0910a2
Simplify implementation
intitni Nov 9, 2023
17ce115
Fix that overriding model not overriding max token and min reply token
intitni Nov 9, 2023
bb3d534
Update
intitni Nov 9, 2023
f0b2a24
Update
intitni Nov 9, 2023
e54c85f
Update
intitni Nov 9, 2023
12bc66b
Update
intitni Nov 9, 2023
21985b9
Update appcast.xml
intitni Nov 9, 2023
fa7dc18
Merge branch 'release/0.27.0'
intitni Nov 9, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
141 changes: 94 additions & 47 deletions Core/Sources/ChatGPTChatTab/ChatPanel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,12 @@ private struct ListHeightPreferenceKey: PreferenceKey {

struct ChatPanelMessages: View {
let chat: StoreOf<Chat>
@State var pinnedToBottom = true
@State var isScrollToBottomButtonDisplayed = true
@State var isPinnedToBottom = true
@Namespace var bottomID
@Namespace var scrollSpace
@State var scrollOffset: Double = 0
@State var listHeight: Double = 0
@State var isInitialLoad = true

var body: some View {
ScrollViewReader { proxy in
Expand All @@ -66,19 +66,19 @@ struct ChatPanelMessages: View {
}

Spacer(minLength: 12)
.id(bottomID)
.onAppear {
withAnimation {
proxy.scrollTo(bottomID, anchor: .bottom)
}
proxy.scrollTo(bottomID, anchor: .bottom)
}
.task {
proxy.scrollTo(bottomID, anchor: .bottom)
}
.id(bottomID)
.background(GeometryReader { geo in
let offset = geo.frame(in: .named(scrollSpace)).minY
Color.clear
.preference(
key: ScrollViewOffsetPreferenceKey.self,
value: offset
)
Color.clear.preference(
key: ScrollViewOffsetPreferenceKey.self,
value: offset
)
})
.preference(
key: ListHeightPreferenceKey.self,
Expand All @@ -100,6 +100,17 @@ struct ChatPanelMessages: View {
updatePinningState()
}
.onPreferenceChange(ScrollViewOffsetPreferenceKey.self) { value in
/// I don't know if there is a way to detect that a scroll is triggered by user
let scrollUpToThreshold = listHeight > 0 // sometimes it can suddenly become 0
&& value > listHeight + 32 + 20 // scroll up to a threshold
&& value > scrollOffset // it's scroll up
&& value - scrollOffset < 100 // it's not some mystery jump
/// Scroll up too much and the tracker is lost
let checkerOutOfScope = value <= 0
if checkerOutOfScope || scrollUpToThreshold {
isPinnedToBottom = false
}

scrollOffset = value
updatePinningState()
}
Expand All @@ -114,49 +125,85 @@ struct ChatPanelMessages: View {
}
}
.overlay(alignment: .bottomTrailing) {
WithViewStore(chat, observe: \.history.last) { viewStore in
Button(action: {
withAnimation(.easeInOut(duration: 0.1)) {
proxy.scrollTo(bottomID, anchor: .bottom)
}
}) {
Image(systemName: "arrow.down")
.padding(4)
.background {
Circle()
.fill(.thickMaterial)
.shadow(color: .black.opacity(0.2), radius: 2)
}
.overlay {
Circle().stroke(Color(nsColor: .separatorColor), lineWidth: 1)
}
.foregroundStyle(.secondary)
.padding(4)
}
.keyboardShortcut(.downArrow, modifiers: [.command])
.opacity(pinnedToBottom ? 0 : 1)
.buttonStyle(.plain)
.onChange(of: viewStore.state) { _ in
if pinnedToBottom || isInitialLoad {
if isInitialLoad {
isInitialLoad = false
}
withAnimation {
proxy.scrollTo(bottomID, anchor: .bottom)
}
}
}
scrollToBottomButton(proxy: proxy)
}
.background {
PinToBottomHandler(chat: chat, pinnedToBottom: $isPinnedToBottom) {
proxy.scrollTo(bottomID, anchor: .bottom)
}
}
}
}
}

@MainActor
func updatePinningState() {
if scrollOffset > listHeight + 24 + 100 || scrollOffset <= 0 {
pinnedToBottom = false
} else {
pinnedToBottom = true
// where does the 32 come from?
withAnimation {
isScrollToBottomButtonDisplayed = scrollOffset > listHeight + 32 + 20
|| scrollOffset <= 0
}
}

@ViewBuilder
func scrollToBottomButton(proxy: ScrollViewProxy) -> some View {
Button(action: {
withAnimation(.easeInOut(duration: 0.1)) {
proxy.scrollTo(bottomID, anchor: .bottom)
}
}) {
Image(systemName: "arrow.down")
.padding(4)
.background {
Circle()
.fill(.thickMaterial)
.shadow(color: .black.opacity(0.2), radius: 2)
}
.overlay {
Circle().stroke(Color(nsColor: .separatorColor), lineWidth: 1)
}
.foregroundStyle(.secondary)
.padding(4)
}
.keyboardShortcut(.downArrow, modifiers: [.command])
.opacity(isScrollToBottomButtonDisplayed ? 1 : 0)
.buttonStyle(.plain)
}

struct PinToBottomHandler: View {
let chat: StoreOf<Chat>
@Binding var pinnedToBottom: Bool
let scrollToBottom: () -> Void

@State var isInitialLoad = true

struct PinToBottomRelatedState: Equatable {
var isReceivingMessage: Bool
var lastMessage: ChatMessage?
}

var body: some View {
WithViewStore(chat, observe: {
PinToBottomRelatedState(
isReceivingMessage: $0.isReceivingMessage,
lastMessage: $0.history.last
)
}) { viewStore in
EmptyView()
.onChange(of: viewStore.state.isReceivingMessage) { isReceiving in
if isReceiving {
pinnedToBottom = true
}
}
.onChange(of: viewStore.state.lastMessage) { _ in
if pinnedToBottom || isInitialLoad {
if isInitialLoad {
isInitialLoad = false
}
scrollToBottom()
}
}
}
}
}
}
Expand Down