Skip to content

Commit

Permalink
fix: vertical scrolling over code (#85)
Browse files Browse the repository at this point in the history
* fix: vertical scrolling over code

* fix: scroll to bottom
  • Loading branch information
gluonfield authored Apr 29, 2024
1 parent 652d010 commit 5baa3dd
Show file tree
Hide file tree
Showing 6 changed files with 75 additions and 57 deletions.
17 changes: 17 additions & 0 deletions Enchanted.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
FFBBF48C2B35051D008D611C /* UIImage+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFBBF48B2B35051D008D611C /* UIImage+Extension.swift */; };
FFD5FAD22B8130490055AB51 /* Vortex in Frameworks */ = {isa = PBXBuildFile; productRef = FF464B122B8026DA008E5130 /* Vortex */; };
FFD5FAD52B8130CE0055AB51 /* OllamaKit in Frameworks */ = {isa = PBXBuildFile; productRef = FFD5FAD42B8130CE0055AB51 /* OllamaKit */; };
FFD74E362BDFAA4E0064E71C /* IsScrolling in Frameworks */ = {isa = PBXBuildFile; productRef = FFD74E352BDFAA4E0064E71C /* IsScrolling */; };
FFE21C782B82353A00A69B9C /* SleepTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFE21C772B82353A00A69B9C /* SleepTest.swift */; };
FFE2C8232B9A657A00BD82F3 /* Accessibility.plist in Resources */ = {isa = PBXBuildFile; fileRef = FFE2C8222B9A657A00BD82F3 /* Accessibility.plist */; };
FFEB9CA82BA04304004B1F3D /* NotificationMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFEB9CA72BA04304004B1F3D /* NotificationMessage.swift */; };
Expand Down Expand Up @@ -186,6 +187,7 @@
FF1BC3C52BA0753400A58043 /* Splash in Frameworks */,
FFD5FAD52B8130CE0055AB51 /* OllamaKit in Frameworks */,
FFD5FAD22B8130490055AB51 /* Vortex in Frameworks */,
FFD74E362BDFAA4E0064E71C /* IsScrolling in Frameworks */,
FF10027A2B27B6070011A4DC /* MarkdownUI in Frameworks */,
FF911DF12B98F08800915E94 /* WrappingHStack in Frameworks */,
FF1002662B2653EE0011A4DC /* ActivityIndicatorView in Frameworks */,
Expand Down Expand Up @@ -533,6 +535,7 @@
FF911DF02B98F08800915E94 /* WrappingHStack */,
FF1BC3C42BA0753400A58043 /* Splash */,
FF4A605C2BC3587800D7BD4F /* KeyboardShortcuts */,
FFD74E352BDFAA4E0064E71C /* IsScrolling */,
);
productName = Enchanted;
productReference = FFEC328D2B24779A003E5C04 /* Enchanted.app */;
Expand Down Expand Up @@ -572,6 +575,7 @@
FF911DEF2B98F08800915E94 /* XCRemoteSwiftPackageReference "WrappingHStack" */,
FF1BC3C32BA0753400A58043 /* XCRemoteSwiftPackageReference "Splash" */,
FF4A605B2BC3587800D7BD4F /* XCRemoteSwiftPackageReference "KeyboardShortcuts" */,
FFD74E342BDFAA4E0064E71C /* XCRemoteSwiftPackageReference "IsScrolling" */,
);
productRefGroup = FFEC328E2B24779A003E5C04 /* Products */;
projectDirPath = "";
Expand Down Expand Up @@ -973,6 +977,14 @@
kind = branch;
};
};
FFD74E342BDFAA4E0064E71C /* XCRemoteSwiftPackageReference "IsScrolling" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/fatbobman/IsScrolling";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 1.1.2;
};
};
FFFD00C42B94CA1300392AE6 /* XCRemoteSwiftPackageReference "Magnet" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/AugustDev/Magnet";
Expand Down Expand Up @@ -1027,6 +1039,11 @@
package = FFD5FAD32B8130CE0055AB51 /* XCRemoteSwiftPackageReference "OllamaKit" */;
productName = OllamaKit;
};
FFD74E352BDFAA4E0064E71C /* IsScrolling */ = {
isa = XCSwiftPackageProductDependency;
package = FFD74E342BDFAA4E0064E71C /* XCRemoteSwiftPackageReference "IsScrolling" */;
productName = IsScrolling;
};
FFFD00C52B94CA1300392AE6 /* Magnet */ = {
isa = XCSwiftPackageProductDependency;
package = FFFD00C42B94CA1300392AE6 /* XCRemoteSwiftPackageReference "Magnet" */;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,15 @@
"version" : "5.9.0"
}
},
{
"identity" : "isscrolling",
"kind" : "remoteSourceControl",
"location" : "https://github.com/fatbobman/IsScrolling",
"state" : {
"revision" : "7def8d8f789a326b6f725a76cee8ec3fa69511df",
"version" : "1.1.2"
}
},
{
"identity" : "keyboardshortcuts",
"kind" : "remoteSourceControl",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
enableThreadSanitizer = "YES"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
Expand Down
2 changes: 0 additions & 2 deletions Enchanted/Stores/ConversationStore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,8 @@ final class ConversationStore: Sendable {
)

DispatchQueue.main.async {
withAnimation(.easeInOut(duration: 0.3)) {
self.messages = messages
self.selectedConversation = selectedConversation
}
}
}

Expand Down
14 changes: 6 additions & 8 deletions Enchanted/UI/Shared/Chat/Chat.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import SwiftUI

struct Chat: View {
struct Chat: View, Sendable {
@State private var languageModelStore: LanguageModelStore
@State private var conversationStore: ConversationStore
@State private var appStore: AppStore
Expand Down Expand Up @@ -53,14 +53,12 @@ struct Chat: View {
}

func onConversationTap(_ conversation: ConversationSD) {
withAnimation(.bouncy(duration: 0.3)) {
Task {
try await conversationStore.selectConversation(conversation)
await languageModelStore.setModel(model: conversation.model)
Haptics.shared.mediumTap()
}
showMenu.toggle()
Task {
try await conversationStore.selectConversation(conversation)
await languageModelStore.setModel(model: conversation.model)
Haptics.shared.mediumTap()
}
showMenu.toggle()
}

@MainActor func onStopGenerateTap() {
Expand Down
89 changes: 43 additions & 46 deletions Enchanted/UI/Shared/Chat/Components/MessageListVIew.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,61 +22,58 @@ struct MessageListView: View {
}
}

func createUserContextMenu(_ message: MessageSD) -> ContextMenu<TupleView<(Button<Label<Text, Image>>, Button<Label<Text, Image>>?, Button<Label<Text, Image>>?)>> {
ContextMenu(menuItems: {
Button(action: {Clipboard.shared.setString(message.content)}) {
Label("Copy", systemImage: "doc.on.doc")
}

if message.role == "user" {
Button(action: {
withAnimation { editMessage = message }
}) {
Label("Edit", systemImage: "pencil")
}
}

if editMessage?.id == message.id {
Button(action: {
withAnimation { editMessage = nil }
}) {
Label("Unselect", systemImage: "pencil")
}
}
})
}

var body: some View {
ScrollViewReader { scrollViewProxy in
List(messages, id:\.self) { message in
let userContextMenu = ContextMenu(menuItems: {
Button(action: {Clipboard.shared.setString(message.content)}) {
Label("Copy", systemImage: "doc.on.doc")
}

if message.role == "user" {
Button(action: {
withAnimation { editMessage = message }
}) {
Label("Edit", systemImage: "pencil")
}
}

if editMessage?.id == message.id {
Button(action: {
withAnimation { editMessage = nil }
}) {
Label("Unselect", systemImage: "pencil")
}
}
})
ChatMessageView(
message: message,
editMessage: $editMessage
)
.id(message.id)
.listRowInsets(EdgeInsets())
.listRowSeparator(.hidden)
.padding(.vertical, 10)
.contextMenu(userContextMenu)
.padding(.horizontal, 10)
.runningBorder(animated: message.id == editMessage?.id)
ScrollView {
ForEach(messages) { message in
ChatMessageView(
message: message,
editMessage: $editMessage
)
.listRowInsets(EdgeInsets())
.listRowSeparator(.hidden)
.padding(.vertical, 10)
.contextMenu(createUserContextMenu(message))
.padding(.horizontal, 10)
.runningBorder(animated: message.id == editMessage?.id)
.id(message)
}
}
.scrollContentBackground(.hidden)
.textSelection(.enabled)
.onAppear {
scrollToBottom(scrollViewProxy)
scrollViewProxy.scrollTo(messages.last, anchor: .bottom)
}
.onChange(of: messages) {
scrollToBottom(scrollViewProxy)
.onChange(of: messages) { oldMessages, newMessages in
scrollViewProxy.scrollTo(messages.last, anchor: .bottom)
}
.onChange(of: messages.last?.content) {
scrollToBottom(scrollViewProxy)
scrollViewProxy.scrollTo(messages.last, anchor: .bottom)
}
.listStyle(.inset)
.scrollIndicators(.never)
}
.scrollDismissesKeyboard(.interactively)
}

private func scrollToBottom(_ proxy: ScrollViewProxy) {
guard messages.count > 0 else { return }
proxy.scrollTo(messages[messages.endIndex - 1].id, anchor: .bottom)
}
}

Expand Down

0 comments on commit 5baa3dd

Please sign in to comment.