Skip to content

Commit a667ab8

Browse files
austincondiffLukas PistrolthecoolwinterWouter01
authored
Overlay UI Improvements (#1159)
* Update feature_request.yml * Update feature_request.yml * Update feature_request.yml * Update feature_request.yml * Update feature_request.yml * Update feature_request.yml * Update bug_report.yml * Update bug_report.yml * Update bug_report.yml * Update bug_report.yml * Update pull_request_template.md * Update pull_request_template.md * Update feature_request.yml * Update bug_report.yml * Update feature_request.yml * Update pull_request_template.md * Update .github/pull_request_template.md Co-authored-by: Lukas Pistrol <l.pistrol@gmail.com> * Update .github/ISSUE_TEMPLATE/bug_report.yml Co-authored-by: Lukas Pistrol <l.pistrol@gmail.com> * Refactored quick open view to not use a navigation view so that it looks right. Other UI corrections to improve the design of the overlay. * Improved open quickly list items path design * Cleaned up Open Quickly overlay view. Made UI improvements for command palette. * Add `OverlayView` * Moved to NSTableView for palette results Signed-off-by: Wouter01 <wouterhennen@gmail.com> * Add isEditable back Signed-off-by: Wouter01 <wouterhennen@gmail.com> * Reverted custom textfield to swiftui textfield Signed-off-by: Wouter01 <wouterhennen@gmail.com> * Changed command palette keybinding to ⌘⇧P. Renamed data to options. Renamed queryContent to text. Added alwaysShowOptions parameter. Added optionRowHeight parameter. Showing commands by default when there is no text in command palette. * Change text color when text is present to make highlighted text stand out in open quickly overlay * Selecting the first item automatically in the OverlayView * Merged with latest master * Merged conflicts, fixed resulting issues, changed keybinding for command pallet to ⌘⇧P * Updated CodeEditTextView version * Fixed build issue Signed-off-by: Wouter01 <wouterhennen@gmail.com> --------- Signed-off-by: Wouter01 <wouterhennen@gmail.com> Co-authored-by: Lukas Pistrol <l.pistrol@gmail.com> Co-authored-by: Khan Winter <35942988+thecoolwinter@users.noreply.github.com> Co-authored-by: Wouter01 <wouterhennen@gmail.com>
1 parent 9ffedd7 commit a667ab8

File tree

12 files changed

+425
-313
lines changed

12 files changed

+425
-313
lines changed

CodeEdit.xcodeproj/project.pbxproj

Lines changed: 41 additions & 21 deletions
Large diffs are not rendered by default.

CodeEdit.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
//
2+
// OverlayWindow.swift
3+
// CodeEdit
4+
//
5+
// Created by Khan Winter on 3/17/23.
6+
//
7+
8+
import Foundation
9+
import SwiftUI
10+
11+
struct OverlayView<RowView: View, PreviewView: View, Option: Identifiable & Hashable>: View {
12+
@ViewBuilder
13+
let rowViewBuilder: ((Option) -> RowView)
14+
15+
@ViewBuilder
16+
let previewViewBuilder: ((Option) -> PreviewView)?
17+
18+
@Binding
19+
var options: [Option]
20+
21+
@State
22+
var selection: Option?
23+
24+
@Binding
25+
var text: String
26+
let title: String
27+
let image: Image
28+
let showsPreview: Bool
29+
let onRowClick: ((Option) -> Void)
30+
let onClose: (() -> Void)
31+
let alwaysShowOptions: Bool
32+
let optionRowHeight: CGFloat
33+
34+
init(
35+
title: String,
36+
image: Image,
37+
options: Binding<[Option]>,
38+
text: Binding<String>,
39+
alwaysShowOptions: Bool = false,
40+
optionRowHeight: CGFloat = 30,
41+
content: @escaping ((Option) -> RowView),
42+
preview: ((Option) -> PreviewView)? = nil,
43+
onRowClick: @escaping ((Option) -> Void),
44+
onClose: @escaping () -> Void
45+
) {
46+
self.title = title
47+
self.image = image
48+
self._options = options
49+
self._text = text
50+
self.rowViewBuilder = content
51+
self.previewViewBuilder = preview
52+
self.onRowClick = onRowClick
53+
self.onClose = onClose
54+
self.showsPreview = preview != nil
55+
self.alwaysShowOptions = alwaysShowOptions
56+
self.optionRowHeight = optionRowHeight
57+
}
58+
59+
var body: some View {
60+
VStack(spacing: 0) {
61+
VStack {
62+
HStack(alignment: .center, spacing: 0) {
63+
image
64+
.font(.system(size: 18))
65+
.foregroundColor(.secondary)
66+
.padding(.leading, 1)
67+
.padding(.trailing, 10)
68+
TextField(title, text: $text)
69+
.font(.system(size: 20, weight: .light, design: .default))
70+
.textFieldStyle(.plain)
71+
.onSubmit {
72+
if let selection {
73+
onRowClick(selection)
74+
} else {
75+
NSSound.beep()
76+
}
77+
}
78+
.task(id: options) {
79+
if options.isEmpty {
80+
selection = nil
81+
} else {
82+
if !options.isEmpty {
83+
selection = options.first
84+
}
85+
}
86+
}
87+
}
88+
.padding(.vertical, 12)
89+
.padding(.horizontal, 12)
90+
.foregroundColor(.primary.opacity(0.85))
91+
.background(EffectView(.sidebar, blendingMode: .behindWindow))
92+
}
93+
if !text.isEmpty || alwaysShowOptions == true {
94+
Divider()
95+
.padding(0)
96+
HStack(spacing: 0) {
97+
if options.isEmpty {
98+
Text("No matching options")
99+
.font(.system(size: 17))
100+
.foregroundColor(.secondary)
101+
.frame(maxWidth: showsPreview ? 272 : .infinity, maxHeight: .infinity)
102+
} else {
103+
NSTableViewWrapper(
104+
data: options,
105+
rowHeight: optionRowHeight,
106+
selection: $selection,
107+
itemView: rowViewBuilder
108+
)
109+
.frame(maxWidth: showsPreview ? 272 : .infinity)
110+
}
111+
if showsPreview {
112+
Divider()
113+
if options.isEmpty {
114+
Spacer()
115+
.frame(maxWidth: .infinity)
116+
} else {
117+
if let selection, let previewViewBuilder {
118+
previewViewBuilder(selection)
119+
.frame(maxWidth: .infinity)
120+
} else {
121+
Text("Select an option to preview")
122+
.frame(maxWidth: .infinity)
123+
}
124+
}
125+
}
126+
}
127+
}
128+
}
129+
.overlay {
130+
keyHandlers
131+
}
132+
.background(EffectView(.sidebar, blendingMode: .behindWindow))
133+
.edgesIgnoringSafeArea(.vertical)
134+
.frame(
135+
minWidth: 680,
136+
minHeight: text.isEmpty && !alwaysShowOptions ? 19 : 400,
137+
maxHeight: text.isEmpty && !alwaysShowOptions ? 19 : .infinity
138+
)
139+
}
140+
141+
@ViewBuilder
142+
var keyHandlers: some View {
143+
Button {
144+
onClose()
145+
} label: { EmptyView() }
146+
.opacity(0)
147+
.keyboardShortcut(.escape, modifiers: [])
148+
.accessibilityLabel("Close Overlay")
149+
Button {
150+
guard selection != options.first else {
151+
return
152+
}
153+
if let selection, let index = options.firstIndex(of: selection) {
154+
self.selection = options[index-1]
155+
} else {
156+
selection = options.first
157+
}
158+
} label: { EmptyView() }
159+
.opacity(0)
160+
.keyboardShortcut(.upArrow, modifiers: [])
161+
.accessibilityLabel("Select Up")
162+
Button {
163+
guard selection != options.last else {
164+
return
165+
}
166+
if let selection, let index = options.firstIndex(of: selection) {
167+
168+
self.selection = options[index+1]
169+
} else {
170+
selection = options.first
171+
}
172+
} label: { EmptyView() }
173+
.opacity(0)
174+
.keyboardShortcut(.downArrow, modifiers: [])
175+
.accessibilityLabel("Select Down")
176+
}
177+
}

CodeEdit/Features/CodeFile/CodeFileView.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,11 @@ struct CodeFileView: View {
2424

2525
private var cancellables = [AnyCancellable]()
2626

27-
private let editable: Bool
27+
private let isEditable: Bool
2828

29-
init(codeFile: CodeFileDocument, editable: Bool = true) {
29+
init(codeFile: CodeFileDocument, isEditable: Bool = true) {
3030
self.codeFile = codeFile
31-
self.editable = editable
31+
self.isEditable = isEditable
3232

3333
codeFile
3434
.$content
@@ -75,9 +75,10 @@ struct CodeFileView: View {
7575
tabWidth: $prefs.preferences.textEditing.defaultTabWidth,
7676
lineHeight: $prefs.preferences.textEditing.lineHeightMultiple,
7777
wrapLines: $prefs.preferences.textEditing.wrapLinesToEditorWidth,
78-
cursorPosition: codeFile.$cursorPosition,
78+
cursorPosition: $codeFile.cursorPosition,
7979
useThemeBackground: prefs.preferences.theme.useThemeBackground,
80-
contentInsets: edgeInsets.nsEdgeInsets
80+
contentInsets: edgeInsets.nsEdgeInsets,
81+
isEditable: isEditable
8182
)
8283
.id(codeFile.fileURL)
8384
.background {
@@ -96,7 +97,6 @@ struct CodeFileView: View {
9697

9798
}
9899
}
99-
.disabled(!editable)
100100
// minHeight zero fixes a bug where the app would freeze if the contents of the file are empty.
101101
.frame(minHeight: .zero, maxHeight: .infinity)
102102
.onChange(of: ThemeModel.shared.selectedTheme) { newValue in

CodeEdit/Features/Commands/ViewModels/CommandPaletteViewModel.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,12 @@ final class CommandPaletteViewModel: ObservableObject {
2828
func reset() {
2929
commandQuery = ""
3030
selected = nil
31-
filteredCommands = []
31+
filteredCommands = CommandManager.shared.commands
3232
}
3333

3434
func fetchMatchingCommands(val: String) {
3535
if val == "" {
36-
self.filteredCommands = []
36+
self.filteredCommands = CommandManager.shared.commands
3737
return
3838
}
3939
self.filteredCommands = CommandManager.shared.commands.filter { $0.title.localizedCaseInsensitiveContains(val) }

0 commit comments

Comments
 (0)