mirror of
https://github.com/Aminark/legado-ios.git
synced 2026-10-23 04:11:22 +08:00
- 区分按钮填充与图标颜色,统一书架、书源、搜索和阅读设置的选中态 - 调整编辑器语法高亮、键盘工具栏及统计卡片的浅深色显示 - 适配 RSS 正文和登录网页背景,保留书源自定义样式和页面状态 - 补充外观切换、页面对比度和管理页面的回归测试
87 lines
4.2 KiB
Swift
87 lines
4.2 KiB
Swift
import SwiftUI
|
|
import UIKit
|
|
import WebKit
|
|
import XCTest
|
|
@testable import Legado
|
|
|
|
@MainActor
|
|
final class AppearanceContrastTests: XCTestCase {
|
|
func testLoginWebViewUsesAdaptiveBackgroundBeforeContentArrives() async throws {
|
|
var source = BookSource(bookSourceUrl: "https://appearance.invalid", bookSourceName: "外观测试")
|
|
source.loginUrl = "about:blank"
|
|
let controller = UIHostingController(rootView: SourceLoginView(source: source))
|
|
let window = UIWindow(frame: CGRect(x: 0, y: 0, width: 390, height: 844))
|
|
window.overrideUserInterfaceStyle = .dark
|
|
window.rootViewController = controller
|
|
window.makeKeyAndVisible()
|
|
defer { window.isHidden = true }
|
|
func webView(in view: UIView) -> WKWebView? {
|
|
if let view = view as? WKWebView { return view }
|
|
return view.subviews.lazy.compactMap { webView(in: $0) }.first
|
|
}
|
|
window.layoutIfNeeded()
|
|
for _ in 0..<20 {
|
|
if webView(in: controller.view) != nil { break }
|
|
try await Task.sleep(nanoseconds: 50_000_000)
|
|
}
|
|
let web = try XCTUnwrap(webView(in: controller.view))
|
|
XCTAssertFalse(web.isOpaque)
|
|
for style in [UIUserInterfaceStyle.dark, .light] {
|
|
window.overrideUserInterfaceStyle = style
|
|
window.layoutIfNeeded()
|
|
let traits = UITraitCollection(userInterfaceStyle: style)
|
|
let background = try XCTUnwrap(web.backgroundColor).resolvedColor(with: traits)
|
|
let scroll = try XCTUnwrap(web.scrollView.backgroundColor).resolvedColor(with: traits)
|
|
if style == .dark {
|
|
XCTAssertLessThan(luminance(background), 0.15)
|
|
XCTAssertLessThan(luminance(scroll), 0.15)
|
|
} else {
|
|
XCTAssertGreaterThan(luminance(background), 0.6)
|
|
XCTAssertGreaterThan(luminance(scroll), 0.6)
|
|
}
|
|
}
|
|
}
|
|
|
|
func testSyntaxTokensHaveReadableContrastInBaseAndElevatedAppearances() {
|
|
let samples: [(SyntaxCodeEditor.Language, String)] = [
|
|
(.json, #"{"title":"正文","count":12,"enabled":true,"empty":null}"#),
|
|
(.rule, "@css:div && $.title {{key}} ##"),
|
|
(.regex, #"\d+.*(word){2,4}"#),
|
|
(.javascript, "// comment\nconst value = 'text'; return 123; /* comment */")
|
|
]
|
|
for style in [UIUserInterfaceStyle.light, .dark] {
|
|
for level in [UIUserInterfaceLevel.base, .elevated] {
|
|
let traits = UITraitCollection(traitsFrom: [
|
|
UITraitCollection(userInterfaceStyle: style),
|
|
UITraitCollection(userInterfaceLevel: level)
|
|
])
|
|
for (language, text) in samples {
|
|
let editor = SyntaxCodeEditor(text: .constant(text), language: language)
|
|
let view = UITextView()
|
|
view.overrideUserInterfaceStyle = style
|
|
view.text = text
|
|
editor.makeCoordinator().highlight(view)
|
|
let background = UIColor.secondarySystemGroupedBackground.resolvedColor(with: traits)
|
|
view.textStorage.enumerateAttribute(.foregroundColor, in: NSRange(location: 0, length: view.textStorage.length)) { color, _, _ in
|
|
guard let color = color as? UIColor else { return XCTFail("Missing syntax color") }
|
|
let foreground = color.resolvedColor(with: traits)
|
|
let values = [luminance(foreground), luminance(background)].sorted()
|
|
XCTAssertGreaterThanOrEqual((values[1] + 0.05) / (values[0] + 0.05), 4.5,
|
|
"Low contrast for \(language), \(style), \(level)")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private func luminance(_ color: UIColor) -> Double {
|
|
var r: CGFloat = 0, g: CGFloat = 0, b: CGFloat = 0, a: CGFloat = 0
|
|
XCTAssertTrue(color.getRed(&r, green: &g, blue: &b, alpha: &a))
|
|
func linear(_ value: CGFloat) -> Double {
|
|
let value = Double(value)
|
|
return value <= 0.04045 ? value / 12.92 : pow((value + 0.055) / 1.055, 2.4)
|
|
}
|
|
return 0.2126 * linear(r) + 0.7152 * linear(g) + 0.0722 * linear(b)
|
|
}
|
|
}
|