Skip to content

Commit

Permalink
feat: select text on iOS (#97)
Browse files Browse the repository at this point in the history
  • Loading branch information
AugustDev authored May 1, 2024
1 parent a85558e commit 05f84eb
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 26 deletions.
14 changes: 13 additions & 1 deletion Enchanted.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
FF15EF6A2B826C0300D4A541 /* SimpleFloatingButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF15EF692B826C0300D4A541 /* SimpleFloatingButton.swift */; };
FF1BC3C52BA0753400A58043 /* Splash in Frameworks */ = {isa = PBXBuildFile; productRef = FF1BC3C42BA0753400A58043 /* Splash */; };
FF1BC3C72BA0757700A58043 /* SplashSyntaxHighlighter+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF1BC3C62BA0757700A58043 /* SplashSyntaxHighlighter+Extension.swift */; };
FF226A652BE2A0EC00CC91F1 /* SelectTextSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF226A642BE2A0EC00CC91F1 /* SelectTextSheet.swift */; };
FF24B30E2B66BE8500AB618F /* RunningBorder.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF24B30D2B66BE8500AB618F /* RunningBorder.swift */; };
FF2F03422B795E0B00349855 /* Clipboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF2F03412B795E0B00349855 /* Clipboard.swift */; };
FF2F03442B79631800349855 /* Button+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF2F03432B79631800349855 /* Button+Extension.swift */; };
Expand Down Expand Up @@ -122,6 +123,7 @@
FF1002742B278C170011A4DC /* AppStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppStore.swift; sourceTree = "<group>"; };
FF15EF692B826C0300D4A541 /* SimpleFloatingButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimpleFloatingButton.swift; sourceTree = "<group>"; };
FF1BC3C62BA0757700A58043 /* SplashSyntaxHighlighter+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SplashSyntaxHighlighter+Extension.swift"; sourceTree = "<group>"; };
FF226A642BE2A0EC00CC91F1 /* SelectTextSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectTextSheet.swift; sourceTree = "<group>"; };
FF24B30D2B66BE8500AB618F /* RunningBorder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunningBorder.swift; sourceTree = "<group>"; };
FF2F03412B795E0B00349855 /* Clipboard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Clipboard.swift; sourceTree = "<group>"; };
FF2F03432B79631800349855 /* Button+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Button+Extension.swift"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -281,6 +283,14 @@
path = Components;
sourceTree = "<group>";
};
FF226A632BE2A0E100CC91F1 /* Components */ = {
isa = PBXGroup;
children = (
FF226A642BE2A0EC00CC91F1 /* SelectTextSheet.swift */,
);
path = Components;
sourceTree = "<group>";
};
FF38F84D2B7A7B5300546B56 /* MenuBar */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -340,6 +350,7 @@
FF66A51F2B77789300FAAC1E /* iOS */ = {
isa = PBXGroup;
children = (
FF226A632BE2A0E100CC91F1 /* Components */,
FFEC32A92B24797C003E5C04 /* ChatView_iOS.swift */,
);
path = iOS;
Expand Down Expand Up @@ -403,6 +414,7 @@
isa = PBXGroup;
children = (
FFEC32982B24779B003E5C04 /* Enchanted.entitlements */,
FFE2C8222B9A657A00BD82F3 /* Accessibility.plist */,
FFBBF4822B348345008D611C /* Info.plist */,
FFEC32962B24779B003E5C04 /* Assets.xcassets */,
FFEC32A12B24783B003E5C04 /* Application */,
Expand All @@ -414,7 +426,6 @@
FF1002422B25BAC50011A4DC /* Stores */,
FF1002412B25BAAE0011A4DC /* SwiftData */,
FFEC32A52B247879003E5C04 /* UI */,
FFE2C8222B9A657A00BD82F3 /* Accessibility.plist */,
);
path = Enchanted;
sourceTree = "<group>";
Expand Down Expand Up @@ -658,6 +669,7 @@
FF7FBE4C2B78E384000901F7 /* SamplePrompt.swift in Sources */,
FF38F8582B7AB1AD00546B56 /* PanelManager.swift in Sources */,
FF6D82172B9122F9001183A8 /* CompletionInstructionSD.swift in Sources */,
FF226A652BE2A0EC00CC91F1 /* SelectTextSheet.swift in Sources */,
FF10025A2B2624C40011A4DC /* ConversationHistoryListView.swift in Sources */,
FF10026D2B2751760011A4DC /* SettingsView.swift in Sources */,
FF33066C2B83BB31007B33E5 /* SidebarButton.swift in Sources */,
Expand Down
61 changes: 36 additions & 25 deletions Enchanted/UI/Shared/Chat/Components/MessageListVIew.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,41 +16,47 @@ struct MessageListView: View {
var conversationState: ConversationState
var userInitials: String
@Binding var editMessage: MessageSD?
@State private var messageSelected: MessageSD?

func onEditMessageTap() -> (MessageSD) -> Void {
return { message in
editMessage = message
}
}

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
ScrollView {
ForEach(messages) { message in

let contextMenu = ContextMenu(menuItems: {
Button(action: {Clipboard.shared.setString(message.content)}) {
Label("Copy", systemImage: "doc.on.doc")
}

#if os(iOS)
Button(action: { messageSelected = message }) {
Label("Select Text", systemImage: "selection.pin.in.out")
}
#endif

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,
showLoader: conversationState == .loading && messages.last == message,
Expand All @@ -60,7 +66,7 @@ struct MessageListView: View {
.listRowInsets(EdgeInsets())
.listRowSeparator(.hidden)
.padding(.vertical, 10)
.contextMenu(createUserContextMenu(message))
.contextMenu(contextMenu)
.padding(.horizontal, 10)
.runningBorder(animated: message.id == editMessage?.id)
.id(message)
Expand All @@ -76,6 +82,11 @@ struct MessageListView: View {
.onChange(of: messages.last?.content) {
scrollViewProxy.scrollTo(messages.last, anchor: .bottom)
}
#if os(iOS)
.sheet(item: $messageSelected) { message in
SelectTextSheet(message: message)
}
#endif
}
}
}
Expand Down
57 changes: 57 additions & 0 deletions Enchanted/UI/iOS/Components/SelectTextSheet.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
//
// SelectTextSheet.swift
// Enchanted
//
// Created by Augustinas Malinauskas on 01/05/2024.
//

#if os(iOS)
import SwiftUI
import UIKit

struct SelectTextSheet: View {
@Environment(\.presentationMode) var presentationMode
@FocusState private var isTextEditorFocused: Bool

var message: MessageSD
var body: some View {
VStack {
ZStack {
Text("Select Text")
.font(.system(size: 16))
.fontWeight(.bold)

HStack {
Spacer()
Button(action: {}) {
Image(systemName: "x.circle.fill")
.padding(7)
}
.buttonStyle(.plain)
}
.padding()
}

TextEditor(text: .constant(message.content))
.focusable()
.focused($isTextEditorFocused)
.onReceive(NotificationCenter.default.publisher(for: UITextField.textDidBeginEditingNotification)) { obj in
if let textField = obj.object as? UITextView {
textField.selectedTextRange = textField.textRange(from: textField.beginningOfDocument, to: textField.endOfDocument)
}
}

}
.textSelection(.enabled)
.onAppear {
isTextEditorFocused = true
}

}
}

#Preview {
SelectTextSheet(message: MessageSD.sample[0])
}

#endif

0 comments on commit 05f84eb

Please sign in to comment.