Skip to content

Commit a875b92

Browse files
committed
Merge branch 'feature/chat-panel-with-normal-title-bar' into develop
2 parents ffd258c + 1c81ab1 commit a875b92

4 files changed

Lines changed: 70 additions & 83 deletions

File tree

Core/Sources/SuggestionWidget/ChatWindowView.swift

Lines changed: 19 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ private let r: Double = 8
99

1010
struct ChatWindowView: View {
1111
let store: StoreOf<ChatPanelFeature>
12+
let toggleVisibility: (Bool) -> Void
1213

1314
struct OverallState: Equatable {
1415
var isPanelDisplayed: Bool
@@ -28,10 +29,6 @@ struct ChatWindowView: View {
2829
}
2930
) { viewStore in
3031
VStack(spacing: 0) {
31-
ChatTitleBar(store: store)
32-
33-
Divider()
34-
3532
ChatTabBar(store: store)
3633
.frame(height: 26)
3734

@@ -41,9 +38,9 @@ struct ChatWindowView: View {
4138
.frame(maxWidth: .infinity, maxHeight: .infinity)
4239
}
4340
.background(.regularMaterial)
44-
.xcodeStyleFrame()
45-
.opacity(viewStore.state.isPanelDisplayed ? 1 : 0)
46-
.frame(minWidth: Style.panelWidth, minHeight: Style.panelHeight)
41+
.onChange(of: viewStore.state.isPanelDisplayed) { isDisplayed in
42+
toggleVisibility(isDisplayed)
43+
}
4744
.preferredColorScheme(viewStore.state.colorScheme)
4845
}
4946
}
@@ -55,20 +52,6 @@ struct ChatTitleBar: View {
5552

5653
var body: some View {
5754
HStack(spacing: 6) {
58-
TrafficLightButton(
59-
isHovering: isHovering,
60-
isActive: true,
61-
color: Color(nsColor: .systemOrange),
62-
action: {
63-
store.send(.hideButtonClicked)
64-
}
65-
) {
66-
Image(systemName: "minus")
67-
.foregroundStyle(.black.opacity(0.5))
68-
.font(Font.system(size: 8).weight(.heavy))
69-
}
70-
.keyboardShortcut("m", modifiers: [.command])
71-
7255
WithViewStore(store, observe: { $0.chatPanelInASeparateWindow }) { viewStore in
7356
TrafficLightButton(
7457
isHovering: isHovering,
@@ -85,6 +68,8 @@ struct ChatTitleBar: View {
8568
}
8669
}
8770

71+
Spacer()
72+
8873
Button(action: {
8974
store.send(.closeActiveTabClicked)
9075
}) {
@@ -93,25 +78,20 @@ struct ChatTitleBar: View {
9378
.opacity(0)
9479
.keyboardShortcut("w", modifiers: [.command])
9580

96-
Spacer()
97-
}
98-
.buttonStyle(.plain)
99-
.overlay {
100-
RoundedRectangle(cornerRadius: 2)
101-
.fill(.tertiary)
102-
.frame(width: 120, height: 4)
103-
.background {
104-
if isHovering {
105-
RoundedRectangle(cornerRadius: 6)
106-
.fill(.tertiary.opacity(0.3))
107-
.frame(width: 128, height: 12)
108-
}
81+
Button(
82+
action: {
83+
store.send(.hideButtonClicked)
10984
}
85+
) {
86+
Image(systemName: "minus")
87+
.foregroundStyle(.black.opacity(0.5))
88+
.font(Font.system(size: 8).weight(.heavy))
89+
}
90+
.opacity(0)
91+
.keyboardShortcut("m", modifiers: [.command])
11092
}
111-
.padding(.horizontal, 6)
112-
.padding(.top, 1)
113-
.frame(maxWidth: .infinity)
114-
.frame(height: Style.chatWindowTitleBarHeight)
93+
.buttonStyle(.plain)
94+
.padding(.leading, 2)
11595
.onHover(perform: { hovering in
11696
isHovering = hovering
11797
})
@@ -453,7 +433,7 @@ struct ChatWindowView_Previews: PreviewProvider {
453433
}
454434

455435
static var previews: some View {
456-
ChatWindowView(store: createStore())
436+
ChatWindowView(store: createStore(), toggleVisibility: { _ in })
457437
.xcodeStyleFrame()
458438
.padding()
459439
.environment(\.chatTabPool, pool)

Core/Sources/SuggestionWidget/FeatureReducers/WidgetFeature.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -581,9 +581,9 @@ public struct WidgetFeature: ReducerProtocol {
581581
windows.toastWindow.alphaValue = noFocus ? 0 : 1
582582

583583
if isChatPanelDetached {
584-
windows.chatPanelWindow.alphaValue = hasChat ? 1 : 0
584+
windows.chatPanelWindow.isWindowHidden = !hasChat
585585
} else {
586-
windows.chatPanelWindow.alphaValue = noFocus ? 0 : 1
586+
windows.chatPanelWindow.isWindowHidden = noFocus
587587
}
588588
} else if let activeApp, activeApp.isExtensionService {
589589
let noFocus = {
@@ -602,18 +602,18 @@ public struct WidgetFeature: ReducerProtocol {
602602
windows.widgetWindow.alphaValue = noFocus ? 0 : 1
603603
windows.toastWindow.alphaValue = noFocus ? 0 : 1
604604
if isChatPanelDetached {
605-
windows.chatPanelWindow.alphaValue = hasChat ? 1 : 0
605+
windows.chatPanelWindow.isWindowHidden = !hasChat
606606
} else {
607-
windows.chatPanelWindow.alphaValue = noFocus && !windows
608-
.chatPanelWindow.isKeyWindow ? 0 : 1
607+
windows.chatPanelWindow.isWindowHidden = noFocus && !windows
608+
.chatPanelWindow.isKeyWindow
609609
}
610610
} else {
611611
windows.sharedPanelWindow.alphaValue = 0
612612
windows.suggestionPanelWindow.alphaValue = 0
613613
windows.widgetWindow.alphaValue = 0
614614
windows.toastWindow.alphaValue = 0
615615
if !isChatPanelDetached {
616-
windows.chatPanelWindow.alphaValue = 0
616+
windows.chatPanelWindow.isWindowHidden = true
617617
}
618618
}
619619
}

Core/Sources/SuggestionWidget/ModuleDependency.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public final class WidgetWindows {
2424
var widgetWindow: NSWindow!
2525
var sharedPanelWindow: NSWindow!
2626
var suggestionPanelWindow: NSWindow!
27-
var chatPanelWindow: NSWindow!
27+
var chatPanelWindow: ChatWindow!
2828
var toastWindow: NSWindow!
2929

3030
nonisolated

Core/Sources/SuggestionWidget/SuggestionWidgetController.swift

Lines changed: 44 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -122,26 +122,52 @@ public final class SuggestionWidgetController: NSObject {
122122
private lazy var chatPanelWindow = {
123123
let it = ChatWindow(
124124
contentRect: .zero,
125-
styleMask: [.resizable],
125+
styleMask: [.resizable, .titled, .miniaturizable],
126126
backing: .buffered,
127127
defer: false
128128
)
129+
it.minimizeWindow = { [weak self] in
130+
self?.store.send(.chatPanel(.hideButtonClicked))
131+
}
132+
it.titleVisibility = .hidden
133+
it.addTitlebarAccessoryViewController({
134+
let controller = NSTitlebarAccessoryViewController()
135+
let view = NSHostingView(rootView: ChatTitleBar(store: store.scope(
136+
state: \.chatPanelState,
137+
action: WidgetFeature.Action.chatPanel
138+
)))
139+
controller.view = view
140+
view.frame = .init(x: 0, y: 0, width: 100, height: 40)
141+
controller.layoutAttribute = .left
142+
return controller
143+
}())
129144
it.isReleasedWhenClosed = false
130145
it.isOpaque = false
131146
it.backgroundColor = .clear
132147
it.level = .init(NSWindow.Level.floating.rawValue + 1)
133-
it.collectionBehavior = [.fullScreenAuxiliary, .transient]
148+
it.collectionBehavior = [
149+
.fullScreenAuxiliary,
150+
.transient,
151+
.fullScreenPrimary,
152+
.fullScreenAllowsTiling,
153+
if #available(macOS 13, *) { [.primary] },
154+
]
134155
it.hasShadow = true
135156
it.contentView = NSHostingView(
136157
rootView: ChatWindowView(
137158
store: store.scope(
138159
state: \.chatPanelState,
139160
action: WidgetFeature.Action.chatPanel
140-
)
161+
),
162+
toggleVisibility: { [weak it] isDisplayed in
163+
guard let window = it else { return }
164+
window.isPanelDisplayed = isDisplayed
165+
}
141166
)
142167
.environment(\.chatTabPool, chatTabPool)
143168
)
144169
it.setIsVisible(true)
170+
it.isPanelDisplayed = false
145171
it.delegate = self
146172
return it
147173
}()
@@ -249,31 +275,6 @@ extension SuggestionWidgetController: NSWindowDelegate {
249275
store.send(.chatPanel(.detachChatPanel))
250276
}
251277
}
252-
253-
public func windowDidBecomeKey(_ notification: Notification) {
254-
guard (notification.object as? NSWindow) === chatPanelWindow else { return }
255-
let screenFrame = NSScreen.screens.first(where: { $0.frame.origin == .zero })?
256-
.frame ?? .zero
257-
var mouseLocation = NSEvent.mouseLocation
258-
let windowFrame = chatPanelWindow.frame
259-
if mouseLocation.y > windowFrame.maxY - Style.chatWindowTitleBarHeight,
260-
mouseLocation.y < windowFrame.maxY,
261-
mouseLocation.x > windowFrame.minX,
262-
mouseLocation.x < windowFrame.maxX
263-
{
264-
mouseLocation.y = screenFrame.size.height - mouseLocation.y
265-
if let cgEvent = CGEvent(
266-
mouseEventSource: nil,
267-
mouseType: .leftMouseDown,
268-
mouseCursorPosition: mouseLocation,
269-
mouseButton: .left
270-
),
271-
let event = NSEvent(cgEvent: cgEvent)
272-
{
273-
chatPanelWindow.performDrag(with: event)
274-
}
275-
}
276-
}
277278
}
278279

279280
// MARK: - Window Subclasses
@@ -288,16 +289,22 @@ class ChatWindow: NSWindow {
288289
override var canBecomeKey: Bool { true }
289290
override var canBecomeMain: Bool { true }
290291

291-
override func mouseDown(with event: NSEvent) {
292-
let windowFrame = frame
293-
let currentLocation = event.locationInWindow
294-
if currentLocation.y > windowFrame.size.height - Style.chatWindowTitleBarHeight,
295-
currentLocation.y < windowFrame.size.height,
296-
currentLocation.x > 0,
297-
currentLocation.x < windowFrame.width
298-
{
299-
performDrag(with: event)
292+
var minimizeWindow: () -> Void = {}
293+
294+
var isWindowHidden: Bool = false {
295+
didSet {
296+
alphaValue = isPanelDisplayed && !isWindowHidden ? 1 : 0
300297
}
301298
}
299+
300+
var isPanelDisplayed: Bool = false {
301+
didSet {
302+
alphaValue = isPanelDisplayed && !isWindowHidden ? 1 : 0
303+
}
304+
}
305+
306+
override func miniaturize(_: Any?) {
307+
minimizeWindow()
308+
}
302309
}
303310

0 commit comments

Comments
 (0)