Skip to content

Commit 4453119

Browse files
committed
Add a light mode to suggestion panel
1 parent 6c1245a commit 4453119

File tree

3 files changed

+191
-79
lines changed

3 files changed

+191
-79
lines changed

Core/Sources/SuggestionWidget/SuggestionPanelView.swift

Lines changed: 62 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import Environment
21
import SwiftUI
2+
import XPCShared
33

44
@MainActor
55
final class SuggestionPanelViewModel: ObservableObject {
@@ -20,6 +20,7 @@ final class SuggestionPanelViewModel: ObservableObject {
2020
@Published var suggestion: Suggestion
2121
@Published var isPanelDisplayed: Bool
2222
@Published var alignTopToAnchor = false
23+
@Published var colorScheme: ColorScheme
2324

2425
var onAcceptButtonTapped: (() -> Void)?
2526
var onRejectButtonTapped: (() -> Void)?
@@ -29,13 +30,15 @@ final class SuggestionPanelViewModel: ObservableObject {
2930
public init(
3031
suggestion: Suggestion = .empty,
3132
isPanelDisplayed: Bool = false,
33+
colorScheme: ColorScheme = .dark,
3234
onAcceptButtonTapped: (() -> Void)? = nil,
3335
onRejectButtonTapped: (() -> Void)? = nil,
3436
onPreviousButtonTapped: (() -> Void)? = nil,
3537
onNextButtonTapped: (() -> Void)? = nil
3638
) {
3739
self.suggestion = suggestion
3840
self.isPanelDisplayed = isPanelDisplayed
41+
self.colorScheme = colorScheme
3942
self.onAcceptButtonTapped = onAcceptButtonTapped
4043
self.onRejectButtonTapped = onRejectButtonTapped
4144
self.onPreviousButtonTapped = onPreviousButtonTapped
@@ -46,7 +49,8 @@ final class SuggestionPanelViewModel: ObservableObject {
4649
struct SuggestionPanelView: View {
4750
@ObservedObject var viewModel: SuggestionPanelViewModel
4851
@State var codeHeight: Double = 0
49-
let backgroundColor = #colorLiteral(red: 0.1580096483, green: 0.1730263829, blue: 0.2026666105, alpha: 1)
52+
// get color scheme
53+
@Environment(\.colorScheme) var colorScheme
5054

5155
var body: some View {
5256
VStack {
@@ -60,8 +64,18 @@ struct SuggestionPanelView: View {
6064
VStack(spacing: 0) {
6165
ScrollView {
6266
CodeBlock(viewModel: viewModel)
67+
.frame(maxWidth: .infinity)
6368
}
64-
.background(Color(nsColor: backgroundColor))
69+
.background(Color(nsColor: {
70+
switch viewModel.colorScheme {
71+
case .dark:
72+
return #colorLiteral(red: 0.1580096483, green: 0.1730263829, blue: 0.2026666105, alpha: 1)
73+
case .light:
74+
return .white
75+
@unknown default:
76+
return .white
77+
}
78+
}()))
6579

6680
ToolBar(viewModel: viewModel)
6781
}
@@ -79,7 +93,7 @@ struct SuggestionPanelView: View {
7993
.padding(1)
8094
)
8195
.allowsHitTesting(viewModel.isPanelDisplayed && !viewModel.suggestion.code.isEmpty)
82-
.preferredColorScheme(.dark)
96+
.preferredColorScheme(viewModel.colorScheme)
8397

8498
if viewModel.alignTopToAnchor {
8599
Spacer()
@@ -106,7 +120,7 @@ struct CodeBlock: View {
106120
HStack(alignment: .firstTextBaseline) {
107121
Text("\(index + viewModel.suggestion.startLineIndex + 1)")
108122
.multilineTextAlignment(.trailing)
109-
.foregroundColor(Color.white.opacity(0.6))
123+
.foregroundColor(.secondary)
110124
.frame(minWidth: 40)
111125
Text(AttributedString(viewModel.suggestion.code[index]))
112126
.foregroundColor(.white.opacity(0.1))
@@ -128,13 +142,7 @@ struct ToolBar: View {
128142
var body: some View {
129143
HStack {
130144
Button(action: {
131-
Task {
132-
if let block = viewModel.onPreviousButtonTapped {
133-
block()
134-
return
135-
}
136-
try await Environment.triggerAction("Previous Suggestion")
137-
}
145+
viewModel.onPreviousButtonTapped?()
138146
}) {
139147
Image(systemName: "chevron.left")
140148
}.buttonStyle(.plain)
@@ -145,39 +153,21 @@ struct ToolBar: View {
145153
.monospacedDigit()
146154

147155
Button(action: {
148-
Task {
149-
if let block = viewModel.onNextButtonTapped {
150-
block()
151-
return
152-
}
153-
try await Environment.triggerAction("Next Suggestion")
154-
}
156+
viewModel.onNextButtonTapped?()
155157
}) {
156158
Image(systemName: "chevron.right")
157159
}.buttonStyle(.plain)
158160

159161
Spacer()
160162

161163
Button(action: {
162-
Task {
163-
if let block = viewModel.onRejectButtonTapped {
164-
block()
165-
return
166-
}
167-
try await Environment.triggerAction("Reject Suggestion")
168-
}
164+
viewModel.onRejectButtonTapped?()
169165
}) {
170166
Text("Reject")
171167
}.buttonStyle(CommandButtonStyle(color: .gray))
172168

173169
Button(action: {
174-
Task {
175-
if let block = viewModel.onAcceptButtonTapped {
176-
block()
177-
return
178-
}
179-
try await Environment.triggerAction("Accept Suggestion")
180-
}
170+
viewModel.onAcceptButtonTapped?()
181171
}) {
182172
Text("Accept")
183173
}.buttonStyle(CommandButtonStyle(color: .indigo))
@@ -208,7 +198,41 @@ struct CommandButtonStyle: ButtonStyle {
208198
}
209199
}
210200

211-
struct SuggestionPanelView_Preview: PreviewProvider {
201+
struct SuggestionPanelView_Dark_Preview: PreviewProvider {
202+
static var previews: some View {
203+
SuggestionPanelView(viewModel: .init(
204+
suggestion: .init(
205+
startLineIndex: 8,
206+
code: highlighted(
207+
code: """
208+
LazyVGrid(columns: [GridItem(.fixed(30)), GridItem(.flexible())]) {
209+
ForEach(0..<viewModel.suggestion.count, id: \\.self) { index in // lkjaskldjalksjdlkasjdlkajslkdjas
210+
Text(viewModel.suggestion[index])
211+
.frame(maxWidth: .infinity, alignment: .leading)
212+
.multilineTextAlignment(.leading)
213+
}
214+
""",
215+
language: "swift",
216+
brightMode: false
217+
),
218+
suggestionCount: 2,
219+
currentSuggestionIndex: 0
220+
),
221+
isPanelDisplayed: true,
222+
colorScheme: .dark
223+
))
224+
.frame(width: 450, height: 400)
225+
.background {
226+
HStack {
227+
Color.red
228+
Color.green
229+
Color.blue
230+
}
231+
}
232+
}
233+
}
234+
235+
struct SuggestionPanelView_Bright_Preview: PreviewProvider {
212236
static var previews: some View {
213237
SuggestionPanelView(viewModel: .init(
214238
suggestion: .init(
@@ -222,12 +246,14 @@ struct SuggestionPanelView_Preview: PreviewProvider {
222246
.multilineTextAlignment(.leading)
223247
}
224248
""",
225-
language: "swift"
249+
language: "swift",
250+
brightMode: true
226251
),
227252
suggestionCount: 2,
228253
currentSuggestionIndex: 0
229254
),
230-
isPanelDisplayed: true
255+
isPanelDisplayed: true,
256+
colorScheme: .light
231257
))
232258
.frame(width: 450, height: 400)
233259
.background {

Core/Sources/SuggestionWidget/SuggestionWidgetController.swift

Lines changed: 87 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,14 @@ public final class SuggestionWidgetController {
6565
let widgetViewModel = WidgetViewModel()
6666
let suggestionPanelViewModel = SuggestionPanelViewModel()
6767

68-
private var userDefaultsObserver = UserDefaultsObserver()
68+
private var presentationModeChangeObserver = UserDefaultsObserver()
69+
private var colorSchemeChangeObserver = UserDefaultsObserver()
6970
private var windowChangeObservationTask: Task<Void, Error>?
7071
private var activeApplicationMonitorTask: Task<Void, Error>?
7172
private var sourceEditorMonitorTask: Task<Void, Error>?
7273
private var suggestionForFiles: [URL: Suggestion] = [:]
7374
private var currentFileURL: URL?
75+
private var colorScheme: ColorScheme = .light
7476

7577
public var onAcceptButtonTapped: (() -> Void)? {
7678
get { suggestionPanelViewModel.onAcceptButtonTapped }
@@ -126,17 +128,61 @@ public final class SuggestionWidgetController {
126128
}
127129

128130
Task { @MainActor in
129-
userDefaultsObserver.onChange = { [weak self] in
131+
presentationModeChangeObserver.onChange = { [weak self] in
130132
guard let self else { return }
131133
self.updateWindowLocation()
132134
}
135+
133136
UserDefaults.shared.addObserver(
134-
userDefaultsObserver,
137+
presentationModeChangeObserver,
135138
forKeyPath: SettingsKey.suggestionPresentationMode,
136139
options: .new,
137140
context: nil
138141
)
139142
}
143+
144+
Task { @MainActor in
145+
let updateColorScheme = { @MainActor [weak self] in
146+
guard let self else { return }
147+
let widgetColorScheme = WidgetColorScheme(
148+
rawValue: UserDefaults.shared
149+
.integer(forKey: SettingsKey.widgetColorScheme)
150+
) ?? .system
151+
let systemColorScheme: ColorScheme = NSApp.effectiveAppearance.name == .darkAqua
152+
? .dark
153+
: .light
154+
self.colorScheme = {
155+
switch (widgetColorScheme, systemColorScheme) {
156+
case (.system, .dark), (.dark, _):
157+
return .dark
158+
case (.system, .light), (.light, _):
159+
return .light
160+
case (.system, _):
161+
return .light
162+
}
163+
}()
164+
self.suggestionPanelViewModel.colorScheme = self.colorScheme
165+
}
166+
167+
updateColorScheme()
168+
colorSchemeChangeObserver.onChange = {
169+
updateColorScheme()
170+
}
171+
172+
UserDefaults.shared.addObserver(
173+
colorSchemeChangeObserver,
174+
forKeyPath: SettingsKey.widgetColorScheme,
175+
options: .new,
176+
context: nil
177+
)
178+
179+
UserDefaults.standard.addObserver(
180+
colorSchemeChangeObserver,
181+
forKeyPath: "AppleInterfaceStyle",
182+
options: .new,
183+
context: nil
184+
)
185+
}
140186
}
141187

142188
public func suggestCode(
@@ -150,7 +196,11 @@ public final class SuggestionWidgetController {
150196
if fileURL == currentFileURL || currentFileURL == nil {
151197
suggestionPanelViewModel.suggestion = .init(
152198
startLineIndex: startLineIndex,
153-
code: highlighted(code: code, language: language),
199+
code: highlighted(
200+
code: code,
201+
language: language,
202+
brightMode: colorScheme == .light
203+
),
154204
suggestionCount: suggestionCount,
155205
currentSuggestionIndex: currentSuggestionIndex
156206
)
@@ -212,26 +262,7 @@ public final class SuggestionWidgetController {
212262
}
213263
guard fileURL != currentFileURL else { continue }
214264
currentFileURL = fileURL
215-
guard let suggestion = suggestionForFiles[fileURL] else {
216-
suggestionPanelViewModel.suggestion = .empty
217-
continue
218-
}
219-
220-
switch suggestion {
221-
case let .code(
222-
code,
223-
language,
224-
startLineIndex,
225-
currentSuggestionIndex,
226-
suggestionCount
227-
):
228-
suggestionPanelViewModel.suggestion = .init(
229-
startLineIndex: startLineIndex,
230-
code: highlighted(code: code, language: language),
231-
suggestionCount: suggestionCount,
232-
currentSuggestionIndex: currentSuggestionIndex
233-
)
234-
}
265+
await updateSuggestionsForActiveEditor(fileURL: fileURL)
235266
}
236267
}
237268
}
@@ -348,4 +379,36 @@ public final class SuggestionWidgetController {
348379

349380
hide()
350381
}
382+
383+
private func updateSuggestionsForActiveEditor(fileURL: URL? = nil) async {
384+
guard let fileURL = await {
385+
if let fileURL { return fileURL }
386+
return try? await Environment.fetchCurrentFileURL()
387+
}(),
388+
let suggestion = suggestionForFiles[fileURL]
389+
else {
390+
suggestionPanelViewModel.suggestion = .empty
391+
return
392+
}
393+
394+
switch suggestion {
395+
case let .code(
396+
code,
397+
language,
398+
startLineIndex,
399+
currentSuggestionIndex,
400+
suggestionCount
401+
):
402+
suggestionPanelViewModel.suggestion = .init(
403+
startLineIndex: startLineIndex,
404+
code: highlighted(
405+
code: code,
406+
language: language,
407+
brightMode: colorScheme == .light
408+
),
409+
suggestionCount: suggestionCount,
410+
currentSuggestionIndex: currentSuggestionIndex
411+
)
412+
}
413+
}
351414
}

0 commit comments

Comments
 (0)