Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 42 additions & 7 deletions Allkdic/Views/DictionaryWebView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,13 @@ private struct WebView: NSViewRepresentable {
}

@MainActor
class Coordinator: NSObject, WKNavigationDelegate, WKUIDelegate {
class Coordinator: NSObject, WKNavigationDelegate, WKUIDelegate, NSWindowDelegate {
@Binding var isLoading: Bool
var dictionary: DictionaryType
var lastLoadedURL: String?
weak var webView: WKWebView?
private nonisolated(unsafe) var popoverObserver: NSObjectProtocol?
private var popupWindow: NSWindow?

init(isLoading: Binding<Bool>, dictionary: DictionaryType) {
_isLoading = isLoading
Expand Down Expand Up @@ -131,16 +132,50 @@ private struct WebView: NSViewRepresentable {
self.lastLoadedURL = nil
}

// Naver/Daum 로그인은 팝업 창(window.open)으로 뜨는데, 이걸 외부 브라우저로 보내면
// 로그인 세션 쿠키가 앱의 WKWebView 데이터스토어와 공유되지 않아 로그인이 반영되지 않는다.
// 전달받은 configuration을 그대로 재사용해 같은 데이터스토어를 쓰는 팝업 웹뷰를 앱 안에 띄운다.
func webView(
_: WKWebView,
createWebViewWith _: WKWebViewConfiguration,
for navigationAction: WKNavigationAction,
createWebViewWith configuration: WKWebViewConfiguration,
for _: WKNavigationAction,
windowFeatures _: WKWindowFeatures,
) -> WKWebView? {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The two user-facing login flows are still unverified.

The PR test plan leaves both Naver and Daum login checks unchecked, and compilation/launching does not establish shared cookies, JavaScript-driven closing, manual closing, or the reload that should pick up the new session.

Please complete and record both flows before merging, including successful window.close() and manual-close behavior. A local HTML-fixture test for window.open → popup closure → main-view reload would also be valuable if practical.

if let url = navigationAction.request.url {
NSWorkspace.shared.open(url)
}
return nil
self.popupWindow?.close()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Popup navigation is being handled as main-WebView navigation.

popupWebView.navigationDelegate = self sends the popup's callbacks through logic that mutates the shared isLoading, injects dictionary CSS into the callback's WebView, and calls focusInput() on the main WebView. During login this can make the main loading indicator inaccurate and run main-page presentation behavior for the popup.

The popup only needs uiDelegate = self for window.close(). Either omit its navigation delegate, or guard every main-specific callback with webView === self.webView and give the popup separate navigation handling.


let popupWebView = WKWebView(frame: NSRect(x: 0, y: 0, width: 480, height: 640), configuration: configuration)
popupWebView.navigationDelegate = self

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: The popup WebView reuses the main dictionary Coordinator as both its navigation and UI delegate, but that coordinator is built to drive the single main WebView and owns shared state (isLoading binding, lastLoadedURL, weak webView). During a Naver/Daum login the popup performs multiple navigations (form loads, OAuth redirects) before it closes, and each one will now run through the same delegate callbacks that control the main view — so popup activity can clobber the main view's loading flag / last loaded URL, and the main view's navigation-policy handling will be applied to the popup's redirects. I'd suggest giving the popup its own lightweight delegate object (one that only tracks its window and closes on window.close() / user close) instead of pointing navigationDelegate/uiDelegate at the shared coordinator, so popup navigation events never interfere with the dictionary WebView's state.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At Allkdic/Views/DictionaryWebView.swift, line 147:

<comment>The popup WebView reuses the main dictionary Coordinator as both its navigation and UI delegate, but that coordinator is built to drive the single main WebView and owns shared state (`isLoading` binding, `lastLoadedURL`, `weak webView`). During a Naver/Daum login the popup performs multiple navigations (form loads, OAuth redirects) before it closes, and each one will now run through the same delegate callbacks that control the main view — so popup activity can clobber the main view's loading flag / last loaded URL, and the main view's navigation-policy handling will be applied to the popup's redirects. I'd suggest giving the popup its own lightweight delegate object (one that only tracks its window and closes on `window.close()` / user close) instead of pointing `navigationDelegate`/`uiDelegate` at the shared coordinator, so popup navigation events never interfere with the dictionary WebView's state.</comment>

<file context>
@@ -131,16 +132,50 @@ private struct WebView: NSViewRepresentable {
+      self.popupWindow?.close()
+
+      let popupWebView = WKWebView(frame: NSRect(x: 0, y: 0, width: 480, height: 640), configuration: configuration)
+      popupWebView.navigationDelegate = self
+      popupWebView.uiDelegate = self
+
</file context>

popupWebView.uiDelegate = self

let window = NSWindow(
contentRect: popupWebView.frame,
styleMask: [.titled, .closable, .resizable],
backing: .buffered,
defer: false,
)
window.isReleasedWhenClosed = false
window.title = self.dictionary.title
window.contentView = popupWebView
window.delegate = self
window.center()
window.makeKeyAndOrderFront(nil)
NSApp.activate(ignoringOtherApps: true)

self.popupWindow = window
return popupWebView
}

// 로그인 완료 후 팝업이 스스로 닫힐 때(window.close()) 호출된다.
func webViewDidClose(_: WKWebView) {
self.popupWindow?.close()
}

// 팝업이 어떤 경로로든(로그인 완료, 사용자가 직접 닫기) 닫히면
// 로그인 세션이 반영되도록 메인 웹뷰를 새로고침한다.
func windowWillClose(_ notification: Notification) {
guard notification.object as? NSWindow === self.popupWindow else { return }
self.popupWindow = nil
self.webView?.reload()
}
}
}
Expand Down
Loading