From 26c4f2e5ccdffc3002f9140a4b07cd95d56f16fb Mon Sep 17 00:00:00 2001 From: Chen Date: Thu, 19 Mar 2026 02:22:48 +0800 Subject: [PATCH] =?UTF-8?q?refactor(ui):=20=E6=95=B4=E7=90=86=E4=B8=BB?= =?UTF-8?q?=E7=95=8C=E9=9D=A2=E5=B8=83=E5=B1=80=E5=AE=B9=E5=99=A8=E7=BB=93?= =?UTF-8?q?=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 下放权限引导页面的滚动容器职责 - 合并虚拟显示列表的重复布局实现 - 补齐列表卡片宽度约束避免收缩 --- .../Capture/Views/CaptureChoose.swift | 51 +++++++++-------- .../Features/Sharing/Views/ShareView.swift | 55 ++++++++++--------- .../VirtualDisplay/Views/DisplaysView.swift | 2 +- .../Views/VirtualDisplayView.swift | 49 +++++++++-------- VoidDisplay/Shared/UI/AppListRowCard.swift | 1 + .../UI/ScreenCapturePermissionGuideView.swift | 7 +-- 6 files changed, 88 insertions(+), 77 deletions(-) diff --git a/VoidDisplay/Features/Capture/Views/CaptureChoose.swift b/VoidDisplay/Features/Capture/Views/CaptureChoose.swift index cf89249..6deb41e 100644 --- a/VoidDisplay/Features/Capture/Views/CaptureChoose.swift +++ b/VoidDisplay/Features/Capture/Views/CaptureChoose.swift @@ -219,29 +219,34 @@ struct IsCapturing: View { private var screenCapturePermissionView: some View { @Bindable var bindableCatalog = viewModel.catalog - return ScreenCapturePermissionGuideView( - loadErrorMessage: viewModel.catalog.loadErrorMessage, - onOpenSettings: { - viewModel.openScreenCapturePrivacySettings { url in - openURL(url) - } - }, - onRequestPermission: { - viewModel.requestScreenCapturePermission() - }, - onRefresh: { - viewModel.refreshPermissionAndMaybeLoad() - }, - onRetry: (viewModel.catalog.loadErrorMessage != nil || viewModel.catalog.lastLoadError != nil) ? { - viewModel.loadDisplays() - } : nil, - isDebugInfoExpanded: $bindableCatalog.showDebugInfo, - debugItems: capturePermissionDebugItems, - rootAccessibilityIdentifier: "capture_permission_guide", - openSettingsButtonAccessibilityIdentifier: "capture_open_settings_button", - requestPermissionButtonAccessibilityIdentifier: "capture_request_permission_button", - refreshButtonAccessibilityIdentifier: "capture_refresh_button" - ) + return ScrollView { + ScreenCapturePermissionGuideView( + loadErrorMessage: viewModel.catalog.loadErrorMessage, + onOpenSettings: { + viewModel.openScreenCapturePrivacySettings { url in + openURL(url) + } + }, + onRequestPermission: { + viewModel.requestScreenCapturePermission() + }, + onRefresh: { + viewModel.refreshPermissionAndMaybeLoad() + }, + onRetry: (viewModel.catalog.loadErrorMessage != nil || viewModel.catalog.lastLoadError != nil) ? { + viewModel.loadDisplays() + } : nil, + isDebugInfoExpanded: $bindableCatalog.showDebugInfo, + debugItems: capturePermissionDebugItems, + rootAccessibilityIdentifier: "capture_permission_guide", + openSettingsButtonAccessibilityIdentifier: "capture_open_settings_button", + requestPermissionButtonAccessibilityIdentifier: "capture_request_permission_button", + refreshButtonAccessibilityIdentifier: "capture_refresh_button" + ) + .frame(maxWidth: .infinity, minHeight: 200, alignment: .top) + .appListContentInsets() + } + .frame(maxWidth: .infinity, maxHeight: .infinity) } private var capturePermissionDebugItems: [(title: String, value: String)] { diff --git a/VoidDisplay/Features/Sharing/Views/ShareView.swift b/VoidDisplay/Features/Sharing/Views/ShareView.swift index 4e642d8..0bf5701 100644 --- a/VoidDisplay/Features/Sharing/Views/ShareView.swift +++ b/VoidDisplay/Features/Sharing/Views/ShareView.swift @@ -181,31 +181,36 @@ struct ShareView: View { private var screenCapturePermissionView: some View { @Bindable var bindableCatalog = viewModel.catalog - return ScreenCapturePermissionGuideView( - loadErrorMessage: viewModel.catalog.loadErrorMessage, - onOpenSettings: { - viewModel.openScreenCapturePrivacySettings { url in - openURL(url) - } - }, - onRequestPermission: { - viewModel.requestScreenCapturePermission() - }, - onRefresh: { - viewModel.refreshPermissionAndMaybeLoad() - }, - onRetry: (viewModel.catalog.loadErrorMessage != nil || viewModel.catalog.lastLoadError != nil) ? { - // User-initiated retry: attempt to load the display list. - // If permission is still missing, macOS may prompt here (expected). - viewModel.loadDisplays() - } : nil, - isDebugInfoExpanded: $bindableCatalog.showDebugInfo, - debugItems: sharingPermissionDebugItems, - rootAccessibilityIdentifier: "share_permission_guide", - openSettingsButtonAccessibilityIdentifier: "share_open_settings_button", - requestPermissionButtonAccessibilityIdentifier: "share_request_permission_button", - refreshButtonAccessibilityIdentifier: "share_refresh_button" - ) + return ScrollView { + ScreenCapturePermissionGuideView( + loadErrorMessage: viewModel.catalog.loadErrorMessage, + onOpenSettings: { + viewModel.openScreenCapturePrivacySettings { url in + openURL(url) + } + }, + onRequestPermission: { + viewModel.requestScreenCapturePermission() + }, + onRefresh: { + viewModel.refreshPermissionAndMaybeLoad() + }, + onRetry: (viewModel.catalog.loadErrorMessage != nil || viewModel.catalog.lastLoadError != nil) ? { + // User-initiated retry: attempt to load the display list. + // If permission is still missing, macOS may prompt here (expected). + viewModel.loadDisplays() + } : nil, + isDebugInfoExpanded: $bindableCatalog.showDebugInfo, + debugItems: sharingPermissionDebugItems, + rootAccessibilityIdentifier: "share_permission_guide", + openSettingsButtonAccessibilityIdentifier: "share_open_settings_button", + requestPermissionButtonAccessibilityIdentifier: "share_request_permission_button", + refreshButtonAccessibilityIdentifier: "share_refresh_button" + ) + .frame(maxWidth: .infinity, minHeight: 200, alignment: .top) + .appListContentInsets() + } + .frame(maxWidth: .infinity, maxHeight: .infinity) .accessibilityElement(children: .contain) .accessibilityIdentifier("share_permission_guide") } diff --git a/VoidDisplay/Features/VirtualDisplay/Views/DisplaysView.swift b/VoidDisplay/Features/VirtualDisplay/Views/DisplaysView.swift index 0b4105b..39e2ec0 100644 --- a/VoidDisplay/Features/VirtualDisplay/Views/DisplaysView.swift +++ b/VoidDisplay/Features/VirtualDisplay/Views/DisplaysView.swift @@ -100,7 +100,7 @@ struct DisplaysView: View { accessibilityIdentifier: "display_row_card" ) - return AppListRowCard(model: model) { + return AppListRowCard(model: model, pushTrailingToEdge: false) { EmptyView() } } diff --git a/VoidDisplay/Features/VirtualDisplay/Views/VirtualDisplayView.swift b/VoidDisplay/Features/VirtualDisplay/Views/VirtualDisplayView.swift index b43dd41..641ca60 100644 --- a/VoidDisplay/Features/VirtualDisplay/Views/VirtualDisplayView.swift +++ b/VoidDisplay/Features/VirtualDisplay/Views/VirtualDisplayView.swift @@ -103,28 +103,7 @@ struct VirtualDisplayView: View { .appListContentInsets() } } else if !virtualDisplay.displayConfigs.isEmpty { - if UITestRuntime.isEnabled { - ScrollView { - LazyVStack(spacing: AppUI.List.sectionSpacing) { - ForEach(virtualDisplay.displayConfigs) { config in - virtualDisplayRow(config) - } - } - .appListContentInsets() - } - .accessibilityIdentifier("virtual_displays_list") - .accessibilityValue(Text("\(virtualDisplay.rebuildRequestCount)")) - } else { - ScrollView { - LazyVStack(spacing: AppUI.List.sectionSpacing) { - ForEach(virtualDisplay.displayConfigs) { config in - virtualDisplayRow(config) - } - } - .appListContentInsets() - } - .accessibilityIdentifier("virtual_displays_list") - } + virtualDisplayList } else { ScrollView { ContentUnavailableView( @@ -139,6 +118,21 @@ struct VirtualDisplayView: View { } } + private var virtualDisplayList: some View { + ScrollView { + LazyVStack(spacing: AppUI.List.sectionSpacing) { + ForEach(virtualDisplay.displayConfigs) { config in + virtualDisplayRow(config) + } + } + .appListContentInsets() + } + .accessibilityIdentifier("virtual_displays_list") + .optionalAccessibilityValue( + UITestRuntime.isEnabled ? Text("\(virtualDisplay.rebuildRequestCount)") : nil + ) + } + private var configStoreErrorPanel: some View { VStack(alignment: .leading, spacing: 12) { Label("Virtual Display Config File Unavailable", systemImage: "exclamationmark.triangle.fill") @@ -249,6 +243,17 @@ struct VirtualDisplayView: View { } } +private extension View { + @ViewBuilder + func optionalAccessibilityValue(_ value: Text?) -> some View { + if let value { + accessibilityValue(value) + } else { + self + } + } +} + #Preview { let env = AppBootstrap.makeEnvironment(preview: true, isRunningUnderXCTestOverride: false) VirtualDisplayView(controller: env.virtualDisplay) diff --git a/VoidDisplay/Shared/UI/AppListRowCard.swift b/VoidDisplay/Shared/UI/AppListRowCard.swift index a63509c..a95c199 100644 --- a/VoidDisplay/Shared/UI/AppListRowCard.swift +++ b/VoidDisplay/Shared/UI/AppListRowCard.swift @@ -67,6 +67,7 @@ struct AppListRowCard: View { .frame(minHeight: AppUI.List.rowMinHeight + 8) .padding(.horizontal, AppUI.List.rowHorizontalInset) .padding(.vertical, AppUI.List.rowVerticalInset + 1) + .frame(maxWidth: .infinity, alignment: .leading) .appInteractiveCardStyle(isHovered: isHovered) .onHover { hovered in isHovered = hovered diff --git a/VoidDisplay/Shared/UI/ScreenCapturePermissionGuideView.swift b/VoidDisplay/Shared/UI/ScreenCapturePermissionGuideView.swift index 7a44ef4..604a092 100644 --- a/VoidDisplay/Shared/UI/ScreenCapturePermissionGuideView.swift +++ b/VoidDisplay/Shared/UI/ScreenCapturePermissionGuideView.swift @@ -14,12 +14,7 @@ struct ScreenCapturePermissionGuideView: View { let refreshButtonAccessibilityIdentifier: String? var body: some View { - ScrollView { - permissionPanel - .frame(maxWidth: .infinity, minHeight: 200, alignment: .top) - .appListContentInsets() - } - .frame(maxWidth: .infinity, maxHeight: .infinity) + permissionPanel } private var permissionPanel: some View {