From eb0cc909fb84fa0f621259ed43b4548548447846 Mon Sep 17 00:00:00 2001 From: Makia98 Date: Tue, 12 May 2026 12:30:50 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81=E7=81=B5=E5=8A=A8?= =?UTF-8?q?=E5=B2=9B=E5=AE=BD=E5=BA=A6=E8=AE=BE=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Sources/CodeIsland/L10n.swift | 2 +- Sources/CodeIsland/NotchPanelView.swift | 22 +++++++++++----- Sources/CodeIsland/Settings.swift | 2 +- .../CodeIslandTests/NotchPanelViewTests.swift | 26 +++++++++++++++++++ 4 files changed, 43 insertions(+), 9 deletions(-) diff --git a/Sources/CodeIsland/L10n.swift b/Sources/CodeIsland/L10n.swift index 0d13158b..9aec4817 100644 --- a/Sources/CodeIsland/L10n.swift +++ b/Sources/CodeIsland/L10n.swift @@ -456,7 +456,7 @@ final class L10n: ObservableObject { "max_visible_sessions": "最大显示会话数", "max_visible_sessions_desc": "超出数量的会话将通过滚动查看", "collapsed_width_scale": "灵动岛宽度", - "collapsed_width_scale_desc": "调整非刘海屏幕上灵动岛的收起宽度", + "collapsed_width_scale_desc": "调整灵动岛的收起宽度", "notch_height_mode": "顶部高度对齐", "notch_height_mode_desc": "让面板与真实 notch 高度、菜单栏高度或自定义值对齐", "notch_height_match_notch": "对齐 notch 高度", diff --git a/Sources/CodeIsland/NotchPanelView.swift b/Sources/CodeIsland/NotchPanelView.swift index 22c6fc55..19a4fa09 100644 --- a/Sources/CodeIsland/NotchPanelView.swift +++ b/Sources/CodeIsland/NotchPanelView.swift @@ -1,6 +1,13 @@ import SwiftUI import CodeIslandCore +enum NotchWidthMetrics { + static func effectiveNotchWidth(notchW: CGFloat, collapsedWidthScale: Int) -> CGFloat { + let clampedScale = max(50, min(collapsedWidthScale, 150)) + return notchW * CGFloat(clampedScale) / 100.0 + } +} + struct NotchPanelView: View { var appState: AppState let hasNotch: Bool @@ -46,11 +53,12 @@ struct NotchPanelView: View { /// Minimum wing width needed to display compact bar content private var compactWingWidth: CGFloat { mascotSize + 14 } - /// Effective notch width — applies user scale on non-notch screens (#56). + /// Effective island width — applies user scale on both notch and non-notch screens. private var effectiveNotchW: CGFloat { - guard !hasNotch else { return notchW } - let scale = CGFloat(max(collapsedWidthScale, 50)) / 100.0 - return notchW * scale + NotchWidthMetrics.effectiveNotchWidth( + notchW: notchW, + collapsedWidthScale: collapsedWidthScale + ) } /// Total panel width — adapts based on state and screen geometry @@ -58,7 +66,7 @@ struct NotchPanelView: View { let nw = effectiveNotchW let maxWidth = min(620, screenWidth - 40) if showIdleIndicator { return idleHovered ? nw + compactWingWidth * 2 + 80 : nw + compactWingWidth * 2 } - if !isActive { return hasNotch ? notchW - 20 : nw } + if !isActive { return hasNotch ? nw - 20 : nw } if shouldShowExpanded { return min(max(nw + 200, 580), maxWidth) } let wing = compactWingWidth let extra: CGFloat = appState.status == .idle ? 0 : 20 @@ -75,7 +83,7 @@ struct NotchPanelView: View { HStack(spacing: 0) { CompactLeftWing(appState: appState, expanded: shouldShowExpanded, mascotSize: mascotSize, hasNotch: hasNotch, showToolStatus: showToolStatus) if hasNotch && !shouldShowExpanded { - Spacer(minLength: notchW) + Spacer(minLength: effectiveNotchW) } else if !shouldShowExpanded && showToolStatus { CompactToolStatus(appState: appState) Spacer(minLength: 0) @@ -89,7 +97,7 @@ struct NotchPanelView: View { IdleIndicatorBar( mascotSize: mascotSize, compactWingWidth: compactWingWidth, - notchW: notchW, + notchW: effectiveNotchW, notchHeight: notchHeight, hasNotch: hasNotch, hovered: idleHovered diff --git a/Sources/CodeIsland/Settings.swift b/Sources/CodeIsland/Settings.swift index abca6e8f..301aa569 100644 --- a/Sources/CodeIsland/Settings.swift +++ b/Sources/CodeIsland/Settings.swift @@ -80,7 +80,7 @@ enum SettingsKey { // Tool status display static let showToolStatus = "showToolStatus" // true = detailed, false = simple - // Island collapsed width scale for non-notch screens (percentage: 50–150, default 100) + // Island collapsed width scale (percentage: 50–150, default 100) static let collapsedWidthScale = "collapsedWidthScale" // Default mascot source when no sessions exist (falls back to this instead of always "claude") diff --git a/Tests/CodeIslandTests/NotchPanelViewTests.swift b/Tests/CodeIslandTests/NotchPanelViewTests.swift index 8e0b6d93..498b20de 100644 --- a/Tests/CodeIslandTests/NotchPanelViewTests.swift +++ b/Tests/CodeIslandTests/NotchPanelViewTests.swift @@ -2,6 +2,32 @@ import XCTest @testable import CodeIsland final class NotchPanelViewTests: XCTestCase { + func testEffectiveNotchWidthAppliesCollapsedWidthScale() { + XCTAssertEqual( + NotchWidthMetrics.effectiveNotchWidth(notchW: 200, collapsedWidthScale: 50), + 100, + accuracy: 0.001 + ) + XCTAssertEqual( + NotchWidthMetrics.effectiveNotchWidth(notchW: 200, collapsedWidthScale: 150), + 300, + accuracy: 0.001 + ) + } + + func testEffectiveNotchWidthClampsOutOfRangeScale() { + XCTAssertEqual( + NotchWidthMetrics.effectiveNotchWidth(notchW: 200, collapsedWidthScale: 10), + 100, + accuracy: 0.001 + ) + XCTAssertEqual( + NotchWidthMetrics.effectiveNotchWidth(notchW: 200, collapsedWidthScale: 250), + 300, + accuracy: 0.001 + ) + } + func testShouldTriggerJumpFailureFeedbackWhenAllAttemptsFail() { XCTAssertTrue(shouldTriggerJumpFailureFeedback([false, false, false])) }