From 64ff12dc4c0f001aa5d6e46ab499b9eee8d7f3d3 Mon Sep 17 00:00:00 2001 From: Qiu Yuzhou Date: Sat, 3 Oct 2026 13:25:19 +0800 Subject: [PATCH] =?UTF-8?q?refactor(ui):=20=E9=94=99=E8=AF=AF=E5=BC=B9?= =?UTF-8?q?=E7=AA=97=E6=8C=82=E8=BD=BD=E6=94=B6=E6=88=90=20presentingError?= =?UTF-8?q?s=20modifier?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 五处逐字复制的 10 行 .alert 样板(窗口壳、三个 destination 包装、服务器 分区)各变一行;ErrorAlertPresenter 的挂载边缘收进 UIErrorAlert.swift, 照 WindowActivationPolicy 的 ViewModifier 先例。AppPresentation 文案 映射边缘不动,presenter 所有权与穿透面不变,零行为变化。 --- ShadowsocksX-NG2/App/MainWindowView.swift | 11 +------ ShadowsocksX-NG2/App/ServersView.swift | 11 +------ ShadowsocksX-NG2/App/UIErrorAlert.swift | 30 ++++++++++++++++- .../App/WorkspaceDestinations.swift | 33 ++----------------- 4 files changed, 34 insertions(+), 51 deletions(-) diff --git a/ShadowsocksX-NG2/App/MainWindowView.swift b/ShadowsocksX-NG2/App/MainWindowView.swift index eddb417e..5a8deb8f 100644 --- a/ShadowsocksX-NG2/App/MainWindowView.swift +++ b/ShadowsocksX-NG2/App/MainWindowView.swift @@ -99,16 +99,7 @@ struct MainWindowView: View { .onChange(of: route.destination) { _, destination in if destination != .rules { ruleDraft = nil } } - .alert( - "操作失败", - isPresented: Binding( - get: { shellActionErrors.isPresented }, - set: { if !$0 { shellActionErrors.dismiss() } }) - ) { - Button("好", role: .cancel) {} - } message: { - Text(shellActionErrors.message ?? "") - } + .presentingErrors(shellActionErrors) .alert( "诊断已导出", isPresented: Binding( diff --git a/ShadowsocksX-NG2/App/ServersView.swift b/ShadowsocksX-NG2/App/ServersView.swift index 38ce82cf..a9892b4f 100644 --- a/ShadowsocksX-NG2/App/ServersView.swift +++ b/ShadowsocksX-NG2/App/ServersView.swift @@ -61,16 +61,7 @@ struct ServersView: View { Button("创建") { commitNewGroup() } Button("取消", role: .cancel) { cancelNewGroup() } } - .alert( - "操作失败", - isPresented: Binding( - get: { errors.isPresented }, - set: { if !$0 { errors.dismiss() } }) - ) { - Button("好", role: .cancel) {} - } message: { - Text(errors.message ?? "") - } + .presentingErrors(errors) .confirmationDialog( deleteTitle, isPresented: Binding( diff --git a/ShadowsocksX-NG2/App/UIErrorAlert.swift b/ShadowsocksX-NG2/App/UIErrorAlert.swift index 33d823d2..a067bcbd 100644 --- a/ShadowsocksX-NG2/App/UIErrorAlert.swift +++ b/ShadowsocksX-NG2/App/UIErrorAlert.swift @@ -1,4 +1,4 @@ -import Foundation +import SwiftUI /// 主窗口共享的错误弹窗呈现状态(UI 持有的窗口状态,issue #41):目录工作流 /// module 以 typed error 上抛且不生成本地化文案,这里在呈现边缘统一转换。 @@ -20,3 +20,31 @@ final class ErrorAlertPresenter: ObservableObject { message = nil } } + +/// `ErrorAlertPresenter` 的唯一 alert 挂载边缘:标题固定「操作失败」,文案取 +/// presenter 当前消息。此前这段 10 行样板复制在窗口壳、destination 包装与 +/// 服务器分区共五处;挂载点各自独立呈现,互不冲突。 +private struct PresentingErrors: ViewModifier { + @ObservedObject var presenter: ErrorAlertPresenter + + func body(content: Content) -> some View { + content + .alert( + "操作失败", + isPresented: Binding( + get: { presenter.isPresented }, + set: { if !$0 { presenter.dismiss() } }) + ) { + Button("好", role: .cancel) {} + } message: { + Text(presenter.message ?? "") + } + } +} + +extension View { + /// 挂载共享错误弹窗:present 进 `presenter` 的失败由此统一弹出。 + func presentingErrors(_ presenter: ErrorAlertPresenter) -> some View { + modifier(PresentingErrors(presenter: presenter)) + } +} diff --git a/ShadowsocksX-NG2/App/WorkspaceDestinations.swift b/ShadowsocksX-NG2/App/WorkspaceDestinations.swift index f3c413bf..481cdab8 100644 --- a/ShadowsocksX-NG2/App/WorkspaceDestinations.swift +++ b/ShadowsocksX-NG2/App/WorkspaceDestinations.swift @@ -31,16 +31,7 @@ struct WorkspaceHomeView: View { didOfferLegacyImport = true showLegacyImportSheet = true } - .alert( - "操作失败", - isPresented: Binding( - get: { errors.isPresented }, - set: { if !$0 { errors.dismiss() } }) - ) { - Button("好", role: .cancel) {} - } message: { - Text(errors.message ?? "") - } + .presentingErrors(errors) } } @@ -55,16 +46,7 @@ struct WorkspaceSubscriptionsView: View { errors: errors, onNodesRemoved: onNodesRemoved ) - .alert( - "操作失败", - isPresented: Binding( - get: { errors.isPresented }, - set: { if !$0 { errors.dismiss() } }) - ) { - Button("好", role: .cancel) {} - } message: { - Text(errors.message ?? "") - } + .presentingErrors(errors) } } @@ -80,15 +62,6 @@ struct WorkspaceDiagnosticsView: View { errors: errors, clipboard: clipboard ) - .alert( - "操作失败", - isPresented: Binding( - get: { errors.isPresented }, - set: { if !$0 { errors.dismiss() } }) - ) { - Button("好", role: .cancel) {} - } message: { - Text(errors.message ?? "") - } + .presentingErrors(errors) } }