修 ultracode 扫描确认的 Quick Send 关窗静默失效 + 设备判本机回落
- Quick Send 关主窗口静默失效(ultracode medium,对抗核验为真):MacQuickSend.trigger 只写 pending,而观察 pending 弹发送表单的逻辑全挂在 MacRootView——后台 / 菜单栏常驻(关主窗口、隐藏 Dock)时 MacRootView 未挂载,选完文件无表单、零反馈,正是 Quick Send 的首要场景。修:MacQuickSend 改为自持独立 NSWindow(NSHostingController 托 MacComposeSheet)呈现发送面板,不依赖主窗口——关窗 / 隐藏 Dock 态下热键 ⌃⌥⌘S 与菜单栏「快速发送文件…」均正常。MacRootView 移除 pending 的 onChange + sheet(不再需要) - 设备判本机回落(ultracode 核验 real=false,Mac 上不可达;作防御性对齐 iOS):MacDevicesView.others 由只比 deviceID != selfDeviceID 改为 isSelf——selfDeviceID 非空按 device_id 判、缺失回落按设备名(对齐 iOS isSelf),防边角态下本机误入「其他设备」列表被右键「移除」而吊销自身会话 - 未改:Keychain ad-hoc 重编后 ACL 失效(ultracode low)——纯本地开发内环摩擦(改一行重编即换 cdhash),Phase 6 Developer ID 稳定签名后自消,对最终用户零影响、无安全/正确性后果 - 扫描结论:6 维度里剪贴板安全 / iOS 回归 / 共享 JS 变更 / 后台生命周期 四项 finder 零发现(对抗核验通过);仅 mac-features + auth-build-config 各出一条,核验为真 2 条(本次修 1 + 防御 1)、驳回 1 - 验证:just mac-build(CommilitiaDropMac.app)BUILD SUCCEEDED;iOS 无关(仅改 macOS-only 文件)
This commit is contained in:
@@ -1,31 +1,66 @@
|
||||
#if os(macOS)
|
||||
import AppKit
|
||||
import Observation
|
||||
import SwiftUI
|
||||
|
||||
// Quick Send:全局热键(MacHotkey)或菜单栏触发 → 激活 app + NSOpenPanel 选文件 → 主窗口切到「传输」区
|
||||
// 并弹发送表单选目标设备发送。pending 为待发文件,MacRootView 观察它、présente MacComposeSheet。
|
||||
@Observable
|
||||
// Quick Send:全局热键(MacHotkey)或菜单栏触发 → 激活 app + NSOpenPanel 选文件 → 弹出独立发送面板
|
||||
// (自持 NSWindow 托 MacComposeSheet)选目标设备发送。**自持面板而非挂主窗口的 sheet**:Quick Send 的
|
||||
// 典型场景正是「关主窗口、仅菜单栏 / 热键常驻」,此时主窗口 MacRootView 未挂载、其 sheet 无处可弹(会
|
||||
// 静默失效)——故此处不依赖主窗口,直接以自己的窗口呈现发送表单(ultracode 审查修复)。
|
||||
@MainActor
|
||||
final class MacQuickSend
|
||||
{
|
||||
static let shared = MacQuickSend()
|
||||
private init() {}
|
||||
|
||||
var pending: [URL] = []
|
||||
private var panel: NSWindow?
|
||||
|
||||
// 激活 app + 选文件(主线程同步)。有选中即置 pending,触发主窗口的发送表单。未登录时 MacRootView
|
||||
// 未挂载、表单不出现——Quick Send 仅登录态有意义(菜单项 / 热键均在登录后才提供 / 注册)。
|
||||
// 激活 app + 选文件(主线程同步)。有选中即弹发送面板;无可达设备则提示。
|
||||
static func trigger()
|
||||
{
|
||||
NSApp.activate()
|
||||
let panel = NSOpenPanel()
|
||||
panel.canChooseFiles = true
|
||||
panel.canChooseDirectories = false
|
||||
panel.allowsMultipleSelection = true
|
||||
panel.prompt = "发送"
|
||||
if panel.runModal() == .OK, !panel.urls.isEmpty
|
||||
{
|
||||
shared.pending = panel.urls
|
||||
let p = NSOpenPanel()
|
||||
p.canChooseFiles = true
|
||||
p.canChooseDirectories = false
|
||||
p.allowsMultipleSelection = true
|
||||
p.prompt = "发送"
|
||||
guard p.runModal() == .OK, !p.urls.isEmpty else { return }
|
||||
shared.present(urls: p.urls)
|
||||
}
|
||||
|
||||
private func present(urls: [URL])
|
||||
{
|
||||
let engine = MacBackgroundController.shared.engine
|
||||
guard !engine.sendableDevices().isEmpty else
|
||||
{
|
||||
let alert = NSAlert()
|
||||
alert.messageText = "暂无可达设备"
|
||||
alert.informativeText = "请确保有其他在线设备(或可唤醒的 iOS 设备)。"
|
||||
alert.runModal()
|
||||
return
|
||||
}
|
||||
// 复用 MacComposeSheet(待发文件 + 目标设备选择);发送 / 取消后关面板。
|
||||
let root = MacComposeSheet(urls: urls,
|
||||
onCancel: { [weak self] in self?.close() },
|
||||
onSend:
|
||||
{ [weak self] device in
|
||||
for url in urls { engine.sendFile(to: device, fileURL: url) }
|
||||
self?.close()
|
||||
})
|
||||
.environment(engine)
|
||||
let win = NSWindow(contentViewController: NSHostingController(rootView: root))
|
||||
win.title = "快速发送"
|
||||
win.styleMask = [ .titled, .closable ]
|
||||
win.isReleasedWhenClosed = false
|
||||
win.center()
|
||||
win.makeKeyAndOrderFront(nil)
|
||||
NSApp.activate()
|
||||
panel = win
|
||||
}
|
||||
|
||||
private func close()
|
||||
{
|
||||
panel?.close()
|
||||
panel = nil
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -10,7 +10,6 @@ struct MacRootView: View
|
||||
{
|
||||
@Environment(EngineController.self) private var engine
|
||||
@Environment(AuthManager.self) private var auth
|
||||
@State private var quickSend = MacQuickSend.shared
|
||||
@State private var selection: MacSection = .transfers
|
||||
|
||||
var body: some View
|
||||
@@ -51,23 +50,7 @@ struct MacRootView: View
|
||||
{
|
||||
NoticeOverlay()
|
||||
}
|
||||
// Quick Send(热键 / 菜单栏触发):有待发文件即切到「传输」并弹发送表单。
|
||||
.onChange(of: quickSend.pending)
|
||||
{ _, urls in
|
||||
if !urls.isEmpty { selection = .transfers }
|
||||
}
|
||||
.sheet(isPresented: Binding(get: { !quickSend.pending.isEmpty },
|
||||
set: { if !$0 { quickSend.pending = [] } }))
|
||||
{
|
||||
MacComposeSheet(urls: quickSend.pending,
|
||||
onCancel: { quickSend.pending = [] },
|
||||
onSend:
|
||||
{ device in
|
||||
for url in quickSend.pending { engine.sendFile(to: device, fileURL: url) }
|
||||
quickSend.pending = []
|
||||
})
|
||||
.environment(engine)
|
||||
}
|
||||
// Quick Send(热键 / 菜单栏触发)自持独立发送面板(见 MacQuickSend),不依赖本窗口,故此处无需挂载。
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
@@ -155,7 +138,16 @@ struct MacDevicesView: View
|
||||
|
||||
private var others: [DeviceItem]
|
||||
{
|
||||
engine.devices.filter { $0.deviceID != engine.selfDeviceID }
|
||||
engine.devices.filter { !isSelf($0) }
|
||||
}
|
||||
|
||||
// 判本机:优先按稳定 device_id,selfDeviceID 缺失时回落按设备名(对齐 iOS isSelf,防边角态下本机
|
||||
// 误入「其他设备」列表被右键「移除」而吊销自身会话)。
|
||||
private func isSelf(_ dev: DeviceItem) -> Bool
|
||||
{
|
||||
let selfID = engine.selfDeviceID
|
||||
if !selfID.isEmpty, !dev.deviceID.isEmpty { return dev.deviceID == selfID }
|
||||
return dev.name == engine.deviceName
|
||||
}
|
||||
|
||||
var body: some View
|
||||
|
||||
Reference in New Issue
Block a user