mirror of
https://github.com/Aminark/legado-ios.git
synced 2026-10-24 21:01:22 +08:00
fix(appearance): 完善深色模式和阅读页面对比度
- 区分按钮填充与图标颜色,统一书架、书源、搜索和阅读设置的选中态 - 调整编辑器语法高亮、键盘工具栏及统计卡片的浅深色显示 - 适配 RSS 正文和登录网页背景,保留书源自定义样式和页面状态 - 补充外观切换、页面对比度和管理页面的回归测试
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user