feat(ios): refine native interface and app icon
Unify bottom actions, selection controls, navigation structure, spacing, and theme colors across iOS pages. Replace the app icon with a higher-contrast native-style asset and include its source SVG.
This commit is contained in:
@@ -4,84 +4,86 @@ import XCTest
|
||||
@testable import MultiSimAdmin
|
||||
|
||||
final class AIThemeTests: XCTestCase {
|
||||
func testControlDimensionsMatchIOS() {
|
||||
XCTAssertEqual(AITheme.buttonHeight, 44, accuracy: 0.1)
|
||||
XCTAssertEqual(AITheme.compactButtonHeight, 40, accuracy: 0.1)
|
||||
XCTAssertEqual(AITheme.largeButtonHeight, 50, accuracy: 0.1)
|
||||
XCTAssertEqual(AITheme.toolbarButtonHeight, 38, accuracy: 0.1)
|
||||
XCTAssertEqual(AITheme.buttonRadius, 12, accuracy: 0.1)
|
||||
XCTAssertEqual(AITheme.iconButtonSize, 44, accuracy: 0.1)
|
||||
XCTAssertEqual(AITheme.toolbarButtonMinWidth, 88, accuracy: 0.1)
|
||||
XCTAssertEqual(AITheme.toolbarButtonWidth, 100, accuracy: 0.1)
|
||||
XCTAssertEqual(AITheme.footerSecondaryButtonWidth, 100, accuracy: 0.1)
|
||||
XCTAssertEqual(AITheme.listActionButtonWidth, 72, accuracy: 0.1)
|
||||
XCTAssertEqual(AIButtonStyle.pressedScale, 0.97, accuracy: 0.01)
|
||||
func testControlDimensionsMatchIOS() {
|
||||
XCTAssertEqual(AITheme.buttonHeight, 48, accuracy: 0.1)
|
||||
XCTAssertEqual(AITheme.compactButtonHeight, 44, accuracy: 0.1)
|
||||
XCTAssertEqual(AITheme.largeButtonHeight, 56, accuracy: 0.1)
|
||||
XCTAssertEqual(AITheme.toolbarButtonHeight, 44, accuracy: 0.1)
|
||||
XCTAssertEqual(AITheme.segmentedControlHeight, 44, accuracy: 0.1)
|
||||
XCTAssertEqual(AITheme.buttonRadius, 16, accuracy: 0.1)
|
||||
XCTAssertEqual(AITheme.iconButtonSize, 44, accuracy: 0.1)
|
||||
XCTAssertEqual(AITheme.toolbarButtonMinWidth, 96, accuracy: 0.1)
|
||||
XCTAssertEqual(AITheme.toolbarButtonWidth, 104, accuracy: 0.1)
|
||||
XCTAssertEqual(AITheme.footerSecondaryButtonWidth, 104, accuracy: 0.1)
|
||||
XCTAssertEqual(AITheme.listActionButtonWidth, 84, accuracy: 0.1)
|
||||
XCTAssertEqual(AIButtonStyle.pressedScale, 0.97, accuracy: 0.01)
|
||||
}
|
||||
|
||||
func testBottomActionsFillEqualWidths() {
|
||||
let primary = AIButtonStyle(kind: .primary, size: .regular, fillsWidth: true)
|
||||
let secondary = AIButtonStyle(kind: .secondary, size: .regular, fillsWidth: true)
|
||||
XCTAssertTrue(primary.fillsWidth)
|
||||
XCTAssertTrue(secondary.fillsWidth)
|
||||
}
|
||||
|
||||
func testFixedWidthDrawsInsideTheButtonStyle() {
|
||||
let button = AIButtonStyle(
|
||||
kind: .danger,
|
||||
size: .compact,
|
||||
fixedWidth: AITheme.listActionButtonWidth
|
||||
)
|
||||
|
||||
XCTAssertTrue(button.fillsWidth == false)
|
||||
XCTAssertEqual(AITheme.listActionButtonWidth, 84, accuracy: 0.1)
|
||||
}
|
||||
|
||||
func testToolbarControlsUseUnifiedColorAndGeometry() {
|
||||
let expected: [(Color, Color, CGFloat, CGFloat)] = [
|
||||
(AITheme.control, AITheme.ink, AITheme.toolbarButtonWidth, AITheme.toolbarButtonHeight),
|
||||
(AITheme.primary, AITheme.onPrimary, AITheme.toolbarButtonWidth, AITheme.toolbarButtonHeight),
|
||||
(AITheme.danger, AITheme.onDanger, AITheme.toolbarButtonWidth, AITheme.toolbarButtonHeight),
|
||||
]
|
||||
|
||||
for (background, foreground, width, height) in expected {
|
||||
XCTAssertTrue(background == background)
|
||||
XCTAssertTrue(foreground == foreground)
|
||||
XCTAssertEqual(width, 104, accuracy: 0.1)
|
||||
XCTAssertEqual(height, 44, accuracy: 0.1)
|
||||
}
|
||||
}
|
||||
|
||||
func testBottomActionsFillEqualWidths() {
|
||||
let primary = AIButtonStyle(kind: .primary, size: .regular, fillsWidth: true)
|
||||
let secondary = AIButtonStyle(kind: .secondary, size: .regular, fillsWidth: true)
|
||||
XCTAssertTrue(primary.fillsWidth)
|
||||
XCTAssertTrue(secondary.fillsWidth)
|
||||
}
|
||||
func testButtonKindsHaveDistinctBaseColors() {
|
||||
let colors = [
|
||||
AIButtonStyle.Kind.primary,
|
||||
.secondary,
|
||||
.danger,
|
||||
].map(\.backgroundColor)
|
||||
XCTAssertEqual(Set(colors).count, 3)
|
||||
}
|
||||
|
||||
func testFixedWidthDrawsInsideTheButtonStyle() {
|
||||
let button = AIButtonStyle(
|
||||
kind: .danger,
|
||||
size: .compact,
|
||||
fixedWidth: AITheme.listActionButtonWidth
|
||||
)
|
||||
func testSearchFieldExposesClearAction() throws {
|
||||
let mirror = Mirror(reflecting: AISearchField("搜索", text: .constant("待清理")))
|
||||
let text = try XCTUnwrap(
|
||||
mirror.children.first { $0.label == "_text" }?.value as? Binding<String>)
|
||||
XCTAssertEqual(text.wrappedValue, "待清理")
|
||||
}
|
||||
|
||||
XCTAssertTrue(button.fillsWidth == false)
|
||||
XCTAssertEqual(AITheme.listActionButtonWidth, 72, accuracy: 0.1)
|
||||
}
|
||||
func testDisabledKindsUseReducedButVisibleRendering() {
|
||||
let disabledKinds = [
|
||||
AIButtonStyle.Kind.primary,
|
||||
.secondary,
|
||||
.danger,
|
||||
]
|
||||
let disabledColors = disabledKinds.map { $0.backgroundColor(isEnabled: false) }
|
||||
|
||||
func testToolbarControlsUseUnifiedColorAndGeometry() {
|
||||
let expected: [(Color, Color, CGFloat, CGFloat)] = [
|
||||
(AITheme.surface, AITheme.ink, AITheme.toolbarButtonWidth, AITheme.toolbarButtonHeight),
|
||||
(AITheme.primary, .white, AITheme.toolbarButtonWidth, AITheme.toolbarButtonHeight),
|
||||
(AITheme.danger, .white, AITheme.toolbarButtonWidth, AITheme.toolbarButtonHeight),
|
||||
]
|
||||
|
||||
for (background, foreground, width, height) in expected {
|
||||
XCTAssertTrue(background == background)
|
||||
XCTAssertTrue(foreground == foreground)
|
||||
XCTAssertEqual(width, 100, accuracy: 0.1)
|
||||
XCTAssertEqual(height, 38, accuracy: 0.1)
|
||||
}
|
||||
}
|
||||
|
||||
func testButtonKindsHaveDistinctBaseColors() {
|
||||
let colors = [
|
||||
AIButtonStyle.Kind.primary,
|
||||
.secondary,
|
||||
.danger
|
||||
].map(\.backgroundColor)
|
||||
XCTAssertEqual(Set(colors).count, 3)
|
||||
}
|
||||
|
||||
func testSearchFieldExposesClearAction() throws {
|
||||
let mirror = Mirror(reflecting: AISearchField("搜索", text: .constant("待清理")))
|
||||
let text = try XCTUnwrap(mirror.children.first { $0.label == "_text" }?.value as? Binding<String>)
|
||||
XCTAssertEqual(text.wrappedValue, "待清理")
|
||||
}
|
||||
|
||||
func testDisabledKindsUseReducedButVisibleRendering() {
|
||||
let disabledKinds = [
|
||||
AIButtonStyle.Kind.primary,
|
||||
.secondary,
|
||||
.danger
|
||||
]
|
||||
let disabledColors = disabledKinds.map { $0.backgroundColor(isEnabled: false) }
|
||||
|
||||
XCTAssertEqual(Set(disabledColors).count, disabledKinds.count)
|
||||
XCTAssertEqual(
|
||||
disabledKinds.map { $0.foregroundColor(isEnabled: false) },
|
||||
[
|
||||
.white.opacity(0.72),
|
||||
AITheme.muted,
|
||||
.white.opacity(0.72)
|
||||
]
|
||||
)
|
||||
}
|
||||
XCTAssertEqual(Set(disabledColors), [AITheme.control])
|
||||
XCTAssertEqual(
|
||||
disabledKinds.map { $0.foregroundColor(isEnabled: false) },
|
||||
[
|
||||
AITheme.muted,
|
||||
AITheme.muted,
|
||||
AITheme.muted,
|
||||
]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user