Merge branch 'main' of https://github.com/Ebullioscopic/Atoll into feature/lunar-support

conflict resolution needed
This commit is contained in:
Hariharan Mudaliar 2026-03-19 22:26:07 +05:30
commit 9396a5a8ff
No known key found for this signature in database
GPG key ID: 025583EB0BE5640E
4 changed files with 78 additions and 16 deletions

View file

@ -158,9 +158,13 @@ struct NotchNotesView: View {
return
}
// Fallback to text if not editing and clipboard has text
if !isEditingNewNote && selectedNoteId == nil {
if let text = pasteboard.string(forType: .string) {
// Handle text paste
if let text = pasteboard.string(forType: .string) {
if isEditingNewNote || selectedNoteId != nil {
// In editor: insert text at the end of content since we intercepted the shortcut
editorContent.append(text)
} else {
// Not in editor: create a new note with the pasted text
createNoteWithContent(text)
}
}

View file

@ -204,6 +204,25 @@ struct ChatMessagesView: View {
Spacer()
Button(action: {
screenAssistantManager.resetConversationContext()
}) {
HStack(spacing: 6) {
Image(systemName: "arrow.counterclockwise")
.font(.caption)
Text("Reset Context")
.font(.caption)
}
.foregroundColor(.secondary)
.padding(.horizontal, 8)
.padding(.vertical, 5)
.background(Color.gray.opacity(0.12))
.cornerRadius(8)
}
.disabled(screenAssistantManager.isLoading)
.buttonStyle(PlainButtonStyle())
.help("Clear conversation and attachments")
Button(action: {
screenAssistantManager.closePanels()
}) {

View file

@ -6558,27 +6558,27 @@ struct ClipboardSettings: View {
HStack {
Text("Display Mode")
Spacer()
Picker("Display Mode", selection: $clipboardDisplayMode) {
Picker("", selection: $clipboardDisplayMode) {
ForEach(ClipboardDisplayMode.allCases, id: \.self) { mode in
Text(mode.displayName).tag(mode)
}
}
.pickerStyle(.menu)
.frame(width: 100)
.frame(minWidth: 100)
}
.settingsHighlight(id: highlightID("Display Mode"))
HStack {
Text("History Size")
Spacer()
Picker("History Size", selection: $clipboardHistorySize) {
Picker("", selection: $clipboardHistorySize) {
Text("3 items").tag(3)
Text("5 items").tag(5)
Text("7 items").tag(7)
Text("10 items").tag(10)
}
.pickerStyle(.menu)
.frame(width: 100)
.frame(minWidth: 100)
}
.settingsHighlight(id: highlightID("History Size"))
@ -6769,13 +6769,13 @@ struct ScreenAssistantSettings: View {
HStack {
Text("Display Mode")
Spacer()
Picker("Display Mode", selection: $screenAssistantDisplayMode) {
Picker("", selection: $screenAssistantDisplayMode) {
ForEach(ScreenAssistantDisplayMode.allCases, id: \.self) { mode in
Text(mode.displayName).tag(mode)
}
}
.pickerStyle(.menu)
.frame(width: 100)
.frame(minWidth: 100)
}
.settingsHighlight(id: highlightID("Display Mode"))
@ -6896,27 +6896,27 @@ struct ColorPickerSettings: View {
HStack {
Text("Display Mode")
Spacer()
Picker("Display Mode", selection: $colorPickerDisplayMode) {
Picker("", selection: $colorPickerDisplayMode) {
ForEach(ColorPickerDisplayMode.allCases, id: \.self) { mode in
Text(mode.displayName).tag(mode)
}
}
.pickerStyle(.menu)
.frame(width: 100)
.frame(minWidth: 100)
}
.settingsHighlight(id: highlightID("Display Mode"))
HStack {
Text("History Size")
Spacer()
Picker("History Size", selection: $colorHistorySize) {
Picker("", selection: $colorHistorySize) {
Text("5 colors").tag(5)
Text("10 colors").tag(10)
Text("15 colors").tag(15)
Text("20 colors").tag(20)
}
.pickerStyle(.menu)
.frame(width: 100)
.frame(minWidth: 100)
}
.settingsHighlight(id: highlightID("History Size"))

View file

@ -120,6 +120,7 @@ class ScreenAssistantManager: NSObject, ObservableObject {
private var audioRecorder: AVAudioRecorder?
private var recordingTimer: Timer?
private var activeRequest: URLSessionTask?
// Panel management
private var chatMessagesPanel: ChatMessagesPanel?
@ -664,10 +665,18 @@ class ScreenAssistantManager: NSObject, ObservableObject {
let task = URLSession.shared.dataTask(with: request) { [weak self] data, response, error in
DispatchQueue.main.async {
guard let self = self else { return }
// Ensure this callback belongs to the current in-flight request
guard self.activeRequest === task else { return }
self.isLoading = false
self.activeRequest = nil
self.handleResponse(data: data, response: response, error: error, provider: provider)
}
}
activeRequest = task
task.resume()
}
@ -690,10 +699,18 @@ class ScreenAssistantManager: NSObject, ObservableObject {
let task = URLSession.shared.dataTask(with: request) { [weak self] data, response, error in
DispatchQueue.main.async {
guard let self = self else { return }
// Ensure this callback belongs to the current in-flight request
guard self.activeRequest === task else { return }
self.isLoading = false
self.activeRequest = nil
self.handleResponse(data: data, response: response, error: error, provider: .openai)
}
}
activeRequest = task
task.resume()
}
@ -717,17 +734,29 @@ class ScreenAssistantManager: NSObject, ObservableObject {
let task = URLSession.shared.dataTask(with: request) { [weak self] data, response, error in
DispatchQueue.main.async {
guard let self = self else { return }
// Ensure this callback belongs to the current in-flight request
guard self.activeRequest === task else { return }
self.isLoading = false
self.activeRequest = nil
self.handleResponse(data: data, response: response, error: error, provider: .claude)
}
}
activeRequest = task
task.resume()
}
// MARK: - Response Handlers
private func handleResponse(data: Data?, response: URLResponse?, error: Error?, provider: AIModelProvider) {
isLoading = false
// Check if the request was cancelled (e.g., by resetConversationContext)
if let error = error as? NSError, error.code == NSURLErrorCancelled {
print("ℹ️ ScreenAssistant: Request was cancelled")
return
}
if let error = error {
print("❌ ScreenAssistant: Network error - \(error)")
@ -1103,7 +1132,17 @@ class ScreenAssistantManager: NSObject, ObservableObject {
}
func clearChat() {
resetConversationContext()
}
func resetConversationContext() {
// Cancel any in-flight request
activeRequest?.cancel()
activeRequest = nil
isLoading = false
chatMessages.removeAll()
clearAllFiles()
}
private func addAssistantMessage(_ content: String) {