fix: 修复 Retina 屏幕截图和翻译结果显示放大问题#12
Conversation
- 预览窗口使用 displayScaleFactor 正确换算像素到点坐标,保持截图与原始选区大小一致 - 翻译等待和结果页面同样使用 backingScaleFactor 计算窗口和图片尺寸 - 移除渲染结果中多余的"译文对照"标题,使原文-译文位置对齐 - 为 HistoryView 的 TextSection 添加 accessibilityLabel 消除未使用参数警告 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
📝 WalkthroughWalkthrough引入 displayScaleFactor 并将多处图像/窗口尺寸计算从像素改为逻辑点(point)单位;在双语结果、预览视图与窗口控制器中传递并使用该因子;同时为历史条目添加无障碍标签,并从 OverlayRenderer 中移除右侧翻译区标题与分隔线。 Changes
Sequence Diagram(s)sequenceDiagram
participant WC as WindowController
participant VM as BilingualResultViewModel
participant V as BilingualResultView
participant Screen as NSScreen
Note over WC,Screen: 计算 displayScaleFactor (backingScaleFactor)
WC->>Screen: read backingScaleFactor
WC->>VM: init(image, displayScaleFactor)
VM-->>WC: imagePointWidth/imagePointHeight
WC->>V: set frame size based on imagePointWidth/height
V->>VM: request image rendering / zoom
VM-->>V: provide image + scale info
Estimated code review effort🎯 3 (中等) | ⏱️ ~25 分钟 Possibly related PRs
诗
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
ScreenTranslate/Features/BilingualResult/BilingualResultWindowController.swift (1)
85-110:⚠️ Potential issue | 🟡 Minor
showResult中displayScaleFactor未同步更新到 viewModel。当
showResult被调用时,仅更新了图片但未更新viewModel.displayScaleFactor。如果屏幕配置在showLoading和showResult之间发生变化(例如用户插拔显示器),可能导致缩放不一致。考虑在
BilingualResultViewModel中添加更新displayScaleFactor的方法,或在showResult时重新创建 viewModel。🛠️ 建议的修复方案
在
BilingualResultViewModel中添加:func showResult(image: CGImage, displayScaleFactor: CGFloat? = nil) { self.image = image if let scaleFactor = displayScaleFactor { self.displayScaleFactor = scaleFactor } self.isLoading = false self.loadingMessage = "" self.errorMessage = nil self.scale = 1.0 }然后在
showResult调用时传入当前的 scaleFactor。
🤖 Fix all issues with AI agents
In `@ScreenTranslate/Features/BilingualResult/BilingualResultViewModel.swift`:
- Line 9: displayScaleFactor is immutable and never updated when the window
moves between DPI scales; make displayScaleFactor a mutable var (remove or relax
private(set)) and ensure you update it whenever you grab the currentScaleFactor
in BilingualResultWindowController.showResult() and in updateImage(): assign
viewModel.displayScaleFactor = currentScaleFactor (or pass currentScaleFactor
into viewModel.showResult(image:) and set there) so the ViewModel uses the
correct scale for image sizing; update the initializer to set a sensible default
but rely on runtime updates in showResult(image:) and updateImage() to keep the
scale in sync.
🧹 Nitpick comments (2)
ScreenTranslate/Features/BilingualResult/BilingualResultWindowController.swift (2)
15-18: 多显示器场景下的缩放因子考量。
currentScaleFactor使用NSScreen.main?.backingScaleFactor,但窗口可能显示在非主显示器上。在主显示器为 Retina(2x)而外接显示器为非 Retina(1x)的场景下,如果窗口实际显示在外接显示器上,计算的尺寸可能不准确。不过考虑到窗口创建时通常会
center()到主屏幕,且这种边界情况影响有限,当前实现是可接受的。
116-160: 考虑提取窗口创建的公共逻辑。
showLoading和show方法中的窗口创建逻辑高度相似,包括:NSWindow 配置、contentView 设置、minSize、collectionBehavior 等。♻️ 建议提取公共方法
private func createWindow(size: NSSize) -> NSWindow { let newWindow = NSWindow( contentRect: NSRect(x: 0, y: 0, width: size.width, height: size.height), styleMask: [.titled, .closable, .miniaturizable, .resizable], backing: .buffered, defer: false ) newWindow.title = String(localized: "bilingualResult.window.title") newWindow.center() newWindow.isReleasedWhenClosed = false newWindow.delegate = self newWindow.minSize = NSSize(width: 400, height: 300) newWindow.collectionBehavior = [.canJoinAllSpaces, .fullScreenAuxiliary] return newWindow }
showResult 和 updateImage 现在接收并更新 displayScaleFactor, 确保窗口在不同 DPI 屏幕间移动后仍使用正确的缩放因子。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In
`@ScreenTranslate/Features/BilingualResult/BilingualResultWindowController.swift`:
- Around line 35-43: The existing showLoading(originalImage:message:) reads
currentScaleFactor into scaleFactor when reusing an already-visible window but
never updates the viewModel with it, so the ViewModel may keep an outdated
displayScaleFactor; inside the reuse branch (where you check if let
existingWindow = window, existingWindow.isVisible) call the appropriate
ViewModel setter/update method or property (e.g., viewModel?.displayScaleFactor
= currentScaleFactor or viewModel?.updateDisplayScaleFactor(currentScaleFactor))
before invoking viewModel?.showLoading(...), ensuring the viewModel's
displayScaleFactor/current scale is synchronized with currentScaleFactor
whenever reusing the window (references: showLoading, currentScaleFactor,
viewModel, window/existingWindow).
| func showLoading(originalImage: CGImage, message: String? = nil) { | ||
| let scaleFactor = currentScaleFactor | ||
|
|
||
| if let existingWindow = window, existingWindow.isVisible { | ||
| viewModel?.showLoading(originalImage: originalImage, message: message) | ||
| existingWindow.makeKeyAndOrderFront(nil) | ||
| NSApp.activate(ignoringOtherApps: true) | ||
| return | ||
| } |
There was a problem hiding this comment.
复用窗口时未同步 displayScaleFactor,可能仍以旧 DPI 渲染。
已有窗口分支里读取了 scaleFactor,但未写回 ViewModel,跨屏后加载态可能仍用旧缩放因子。建议在复用时同步更新。
🔧 建议修改
if let existingWindow = window, existingWindow.isVisible {
+ viewModel?.displayScaleFactor = scaleFactor
viewModel?.showLoading(originalImage: originalImage, message: message)
existingWindow.makeKeyAndOrderFront(nil)
NSApp.activate(ignoringOtherApps: true)
return
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| func showLoading(originalImage: CGImage, message: String? = nil) { | |
| let scaleFactor = currentScaleFactor | |
| if let existingWindow = window, existingWindow.isVisible { | |
| viewModel?.showLoading(originalImage: originalImage, message: message) | |
| existingWindow.makeKeyAndOrderFront(nil) | |
| NSApp.activate(ignoringOtherApps: true) | |
| return | |
| } | |
| func showLoading(originalImage: CGImage, message: String? = nil) { | |
| let scaleFactor = currentScaleFactor | |
| if let existingWindow = window, existingWindow.isVisible { | |
| viewModel?.displayScaleFactor = scaleFactor | |
| viewModel?.showLoading(originalImage: originalImage, message: message) | |
| existingWindow.makeKeyAndOrderFront(nil) | |
| NSApp.activate(ignoringOtherApps: true) | |
| return | |
| } |
🤖 Prompt for AI Agents
In
`@ScreenTranslate/Features/BilingualResult/BilingualResultWindowController.swift`
around lines 35 - 43, The existing showLoading(originalImage:message:) reads
currentScaleFactor into scaleFactor when reusing an already-visible window but
never updates the viewModel with it, so the ViewModel may keep an outdated
displayScaleFactor; inside the reuse branch (where you check if let
existingWindow = window, existingWindow.isVisible) call the appropriate
ViewModel setter/update method or property (e.g., viewModel?.displayScaleFactor
= currentScaleFactor or viewModel?.updateDisplayScaleFactor(currentScaleFactor))
before invoking viewModel?.showLoading(...), ensuring the viewModel's
displayScaleFactor/current scale is synchronized with currentScaleFactor
whenever reusing the window (references: showLoading, currentScaleFactor,
viewModel, window/existingWindow).
Summary
backingScaleFactor将像素尺寸正确换算为点尺寸HistoryView.TextSection的未使用label参数添加accessibilityLabelTest plan
🤖 Generated with Claude Code
Summary by CodeRabbit
发布说明
新功能
改进与优化