mirror of
https://github.com/Aminark/legado-ios.git
synced 2026-10-24 12:51:22 +08:00
fix(appearance): 完善深色模式和阅读页面对比度
- 区分按钮填充与图标颜色,统一书架、书源、搜索和阅读设置的选中态 - 调整编辑器语法高亮、键盘工具栏及统计卡片的浅深色显示 - 适配 RSS 正文和登录网页背景,保留书源自定义样式和页面状态 - 补充外观切换、页面对比度和管理页面的回归测试
This commit is contained in:
@@ -340,6 +340,22 @@ extension View {
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
func readingNavigationBarBackground() -> some View {
|
||||
if #available(iOS 16.0, *), !ReadingCompatibility.usesLegacyUI {
|
||||
toolbarBackground(ReadingTheme.canvas, for: .navigationBar)
|
||||
.toolbarBackground(.visible, for: .navigationBar)
|
||||
} else {
|
||||
background(ReadingUIKitConfiguration { controller in
|
||||
let appearance = UINavigationBarAppearance()
|
||||
appearance.configureWithOpaqueBackground()
|
||||
appearance.backgroundColor = UIColor(ReadingTheme.canvas)
|
||||
controller.navigationController?.navigationBar.standardAppearance = appearance
|
||||
controller.navigationController?.navigationBar.scrollEdgeAppearance = appearance
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
func readingTabBarBackground() -> some View {
|
||||
if #available(iOS 16.0, *), !ReadingCompatibility.usesLegacyUI {
|
||||
|
||||
+29
-2
@@ -77,6 +77,29 @@ private struct ReadingUnavailableLabelStyle: LabelStyle {
|
||||
}
|
||||
|
||||
extension View {
|
||||
/// Keep filled controls dark in both appearances, independently of icon tint.
|
||||
func readingProminentButtonStyle() -> some View {
|
||||
buttonStyle(.borderedProminent)
|
||||
.tint(ReadingTheme.accentFill)
|
||||
.foregroundStyle(ReadingTheme.onAccent)
|
||||
}
|
||||
|
||||
func readingSecondaryButtonStyle() -> some View {
|
||||
buttonStyle(.bordered)
|
||||
.tint(ReadingTheme.accentFill)
|
||||
.foregroundStyle(ReadingTheme.accent)
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
func readingChoiceButtonStyle(isSelected: Bool) -> some View {
|
||||
if isSelected {
|
||||
readingProminentButtonStyle()
|
||||
.accessibilityAddTraits(.isSelected)
|
||||
} else {
|
||||
readingSecondaryButtonStyle()
|
||||
}
|
||||
}
|
||||
|
||||
func readingSearchable(text: Binding<String>, isPresented: Binding<Bool>, prompt: String) -> some View {
|
||||
modifier(ReadingSearchModifier(text: text, isPresented: isPresented, prompt: prompt))
|
||||
}
|
||||
@@ -144,7 +167,11 @@ private struct ReadingSearchModifier: ViewModifier {
|
||||
}
|
||||
|
||||
enum ReadingTheme {
|
||||
static let accent = adaptive(0x171717, dark: 0xF2F2F2)
|
||||
static let accent = adaptive(0x171717, dark: 0xDADAE0)
|
||||
static let accentFill = adaptive(0x171717, dark: 0x414148)
|
||||
static let emphasisSurface = adaptive(0x171717, dark: 0x29292E)
|
||||
static let selectionBorder = adaptive(0x171717, dark: 0x777780)
|
||||
static let toggleTint = Color(uiColor: .systemGreen)
|
||||
static let accentSoft = adaptive(0xEEEEEF, dark: 0x29292C)
|
||||
static let coral = Color(red: 0.76, green: 0.48, blue: 0.27)
|
||||
static let paper = Color(red: 0.965, green: 0.945, blue: 0.895)
|
||||
@@ -153,7 +180,7 @@ enum ReadingTheme {
|
||||
static let groupedCanvas = adaptive(0xF3F3F4, dark: 0x1C1C1F)
|
||||
static let surface = adaptive(0xFFFFFF, dark: 0x232326)
|
||||
static let separator = adaptive(0xE6E6E8, dark: 0x363639)
|
||||
static let onAccent = adaptive(0xFFFFFF, dark: 0x171717)
|
||||
static let onAccent = Color.white
|
||||
|
||||
private static func adaptive(_ light: UInt32, dark: UInt32) -> Color {
|
||||
Color(uiColor: UIColor { traits in
|
||||
|
||||
@@ -47,7 +47,9 @@ struct ReadingStatisticsView: View {
|
||||
}
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.padding(24)
|
||||
.background(ReadingTheme.accent, in: RoundedRectangle(cornerRadius: 20))
|
||||
.background(ReadingTheme.emphasisSurface, in: RoundedRectangle(cornerRadius: 20))
|
||||
.accessibilityElement(children: .contain)
|
||||
.accessibilityIdentifier("statistics.todayCard")
|
||||
}
|
||||
|
||||
private var overviewGrid: some View {
|
||||
|
||||
@@ -194,7 +194,7 @@ struct BookDetailView: View {
|
||||
.font(.body.weight(.medium))
|
||||
.frame(maxWidth: .infinity, minHeight: 28)
|
||||
}
|
||||
.buttonStyle(.borderedProminent)
|
||||
.readingProminentButtonStyle()
|
||||
.disabled(model.chapters.isEmpty)
|
||||
Button {
|
||||
if library.contains(model.book) {
|
||||
@@ -210,7 +210,7 @@ struct BookDetailView: View {
|
||||
.font(.subheadline)
|
||||
.frame(maxWidth: dynamicTypeSize.isAccessibilitySize ? .infinity : nil, minHeight: 28)
|
||||
}
|
||||
.buttonStyle(.bordered)
|
||||
.readingSecondaryButtonStyle()
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
|
||||
@@ -155,7 +155,7 @@ struct ExploreView: View {
|
||||
Text("添加带有发现分类的书源,即可在这里浏览书籍。")
|
||||
} actions: {
|
||||
NavigationLink("管理书源") { SourceManagementView() }
|
||||
.buttonStyle(.borderedProminent)
|
||||
.readingProminentButtonStyle()
|
||||
}
|
||||
} else {
|
||||
LazyVStack(spacing: 0) {
|
||||
|
||||
@@ -142,7 +142,7 @@ private struct RSSArticleListView: View {
|
||||
ScrollView(.horizontal, showsIndicators: false) {
|
||||
HStack { ForEach(Array(sorts.enumerated()), id: \.element.id) { index, sort in
|
||||
Button(sort.name.isEmpty ? "默认" : sort.name) { selectedSort = index; Task { await refresh() } }
|
||||
.buttonStyle(.bordered).tint(selectedSort == index ? ReadingTheme.accent : .secondary)
|
||||
.readingChoiceButtonStyle(isSelected: selectedSort == index)
|
||||
}}.padding(.horizontal)
|
||||
}.padding(.vertical, 6)
|
||||
}
|
||||
@@ -435,7 +435,7 @@ private struct RSSDownloadView: View {
|
||||
Image(systemName: "doc.badge.arrow.up").font(.system(size: 48)).foregroundStyle(ReadingTheme.accent)
|
||||
Text(fileName).font(.headline)
|
||||
Text(ByteCountFormatter.string(fromByteCount: Int64(data.count), countStyle: .file)).foregroundStyle(.secondary)
|
||||
Button("选择保存位置", systemImage: "folder") { showsExporter = true }.buttonStyle(.borderedProminent)
|
||||
Button("选择保存位置", systemImage: "folder") { showsExporter = true }.readingProminentButtonStyle()
|
||||
}
|
||||
}.padding().navigationTitle("文件下载").toolbar { ToolbarItem(placement: .cancellationAction) { Button("关闭") { dismiss() } } }
|
||||
.task(id: url) { await download() }
|
||||
@@ -464,7 +464,7 @@ private struct RSSBinaryDocument: FileDocument {
|
||||
func fileWrapper(configuration: WriteConfiguration) throws -> FileWrapper { .init(regularFileWithContents: data) }
|
||||
}
|
||||
|
||||
private struct RSSPhotoView: View {
|
||||
struct RSSPhotoView: View {
|
||||
@Environment(\.dismiss) private var dismiss
|
||||
let value: String
|
||||
let source: RssSource
|
||||
@@ -480,9 +480,13 @@ private struct RSSPhotoView: View {
|
||||
else if loading { ProgressView() }
|
||||
else { ReadingUnavailableView("图片加载失败", systemImage: "photo.badge.exclamationmark") }
|
||||
}.frame(minWidth: proxy.size.width, minHeight: proxy.size.height)
|
||||
}.background(.black)
|
||||
}
|
||||
.background(.black)
|
||||
.environment(\.colorScheme, .dark)
|
||||
.tint(.white)
|
||||
}
|
||||
.navigationTitle(source.sourceName).navigationBarTitleDisplayMode(.inline)
|
||||
.readingNavigationBarBackground()
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .primaryAction) { Button("保存到照片", systemImage: "square.and.arrow.down") { save() }.disabled(image == nil) }
|
||||
ToolbarItem(placement: .confirmationAction) { Button("完成") { dismiss() } }
|
||||
@@ -490,6 +494,7 @@ private struct RSSPhotoView: View {
|
||||
.task(id: value) { await load() }
|
||||
.alert("图片", isPresented: Binding(get: { message != nil }, set: { if !$0 { message = nil } })) { Button("好") { message = nil } } message: { Text(message ?? "") }
|
||||
}
|
||||
.readingTabBarHidden()
|
||||
}
|
||||
|
||||
private func load() async {
|
||||
|
||||
@@ -41,6 +41,9 @@ struct RSSWebReaderView: UIViewRepresentable {
|
||||
controller.addUserScript(.init(source: inject, injectionTime: .atDocumentEnd, forMainFrameOnly: false))
|
||||
}
|
||||
let webView = WKWebView(frame: .zero, configuration: configuration)
|
||||
webView.isOpaque = false
|
||||
webView.backgroundColor = UIColor(ReadingTheme.canvas)
|
||||
webView.scrollView.backgroundColor = UIColor(ReadingTheme.canvas)
|
||||
webView.navigationDelegate = context.coordinator
|
||||
webView.uiDelegate = context.coordinator
|
||||
webView.allowsBackForwardNavigationGestures = true
|
||||
|
||||
@@ -492,7 +492,7 @@ struct ReaderView: View {
|
||||
.accessibilityIdentifier("reader.failureChangeSource")
|
||||
}
|
||||
}
|
||||
.buttonStyle(.bordered)
|
||||
.readingSecondaryButtonStyle()
|
||||
}
|
||||
|
||||
private func openSourceSwitch() {
|
||||
@@ -1118,7 +1118,7 @@ struct ReaderView: View {
|
||||
Image(systemName: "textformat.size.smaller")
|
||||
.frame(width: 38, height: 32)
|
||||
}
|
||||
.buttonStyle(.bordered)
|
||||
.readingSecondaryButtonStyle()
|
||||
|
||||
VStack(spacing: 2) {
|
||||
Text("字号")
|
||||
@@ -1135,7 +1135,7 @@ struct ReaderView: View {
|
||||
Image(systemName: "textformat.size.larger")
|
||||
.frame(width: 38, height: 32)
|
||||
}
|
||||
.buttonStyle(.bordered)
|
||||
.readingSecondaryButtonStyle()
|
||||
}
|
||||
|
||||
HStack(spacing: 8) {
|
||||
@@ -1285,14 +1285,19 @@ struct ReaderView: View {
|
||||
Text(choice.title)
|
||||
.font(.caption2)
|
||||
}
|
||||
.foregroundStyle(pageAnimation == choice.value ? Color.white : Color.primary)
|
||||
.foregroundStyle(pageAnimation == choice.value ? ReadingTheme.onAccent : Color.primary)
|
||||
.frame(width: 58, height: 54)
|
||||
.background(
|
||||
pageAnimation == choice.value ? ReadingTheme.accent : Color.secondary.opacity(0.1),
|
||||
pageAnimation == choice.value ? ReadingTheme.accentFill : Color.secondary.opacity(0.1),
|
||||
in: RoundedRectangle(cornerRadius: 12, style: .continuous)
|
||||
)
|
||||
.overlay {
|
||||
RoundedRectangle(cornerRadius: 12, style: .continuous)
|
||||
.strokeBorder(pageAnimation == choice.value ? ReadingTheme.selectionBorder : .clear, lineWidth: 1)
|
||||
}
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
.accessibilityAddTraits(pageAnimation == choice.value ? .isSelected : [])
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1392,12 +1397,16 @@ struct ReaderView: View {
|
||||
Button(action: action) {
|
||||
Text(title)
|
||||
.font(.caption.weight(.medium))
|
||||
.foregroundStyle(selected ? Color.white : Color.primary)
|
||||
.foregroundStyle(selected ? ReadingTheme.onAccent : Color.primary)
|
||||
.padding(.horizontal, 12)
|
||||
.padding(.vertical, 7)
|
||||
.background(selected ? ReadingTheme.accent : Color.secondary.opacity(0.1), in: Capsule())
|
||||
.background(selected ? ReadingTheme.accentFill : Color.secondary.opacity(0.1), in: Capsule())
|
||||
.overlay {
|
||||
Capsule().strokeBorder(selected ? ReadingTheme.selectionBorder : .clear, lineWidth: 1)
|
||||
}
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
.accessibilityAddTraits(selected ? .isSelected : [])
|
||||
}
|
||||
|
||||
private func valueSlider(
|
||||
|
||||
@@ -39,7 +39,7 @@ struct QRCodeImportView: View {
|
||||
} label: {
|
||||
Label("从照片选择二维码", systemImage: "photo")
|
||||
.frame(maxWidth: .infinity)
|
||||
}.buttonStyle(.borderedProminent).disabled(isReading)
|
||||
}.readingProminentButtonStyle().disabled(isReading)
|
||||
Text("支持 HTTP(S) 链接、Legado 导入深链和 JSON 内容。识别后进入导入流程。")
|
||||
.font(.footnote).foregroundStyle(.secondary)
|
||||
if values.count > 1 {
|
||||
|
||||
@@ -3,6 +3,26 @@ import UIKit
|
||||
|
||||
struct SyntaxCodeEditor: UIViewRepresentable {
|
||||
enum Language { case json, rule, javascript, regex }
|
||||
|
||||
// Syntax colors are text, so they need more contrast than system icon tints.
|
||||
private enum Palette {
|
||||
static let keyword = adaptive(0x7A2BA6, dark: 0xD5A5F5)
|
||||
static let number = adaptive(0x895900, dark: 0xE6B66A)
|
||||
static let operation = adaptive(0xAD285F, dark: 0xF49AB8)
|
||||
static let punctuation = adaptive(0x14666E, dark: 0x83CED8)
|
||||
static let string = adaptive(0x2D6B39, dark: 0x8CCF96)
|
||||
static let key = adaptive(0x1E5EB2, dark: 0x93BFFF)
|
||||
static let comment = adaptive(0x64646B, dark: 0xA4A4AE)
|
||||
|
||||
private static func adaptive(_ light: UInt32, dark: UInt32) -> UIColor {
|
||||
UIColor { traits in
|
||||
let hex = traits.userInterfaceStyle == .dark ? dark : light
|
||||
return UIColor(red: CGFloat((hex >> 16) & 0xff) / 255,
|
||||
green: CGFloat((hex >> 8) & 0xff) / 255,
|
||||
blue: CGFloat(hex & 0xff) / 255, alpha: 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
@Binding var text: String
|
||||
var language: Language = .rule
|
||||
|
||||
@@ -13,6 +33,7 @@ struct SyntaxCodeEditor: UIViewRepresentable {
|
||||
view.delegate = context.coordinator
|
||||
view.font = .monospacedSystemFont(ofSize: 14, weight: .regular)
|
||||
view.backgroundColor = .secondarySystemGroupedBackground
|
||||
view.tintColor = UIColor(ReadingTheme.accent)
|
||||
view.textContainerInset = UIEdgeInsets(top: 14, left: 12, bottom: 20, right: 12)
|
||||
view.autocorrectionType = .no
|
||||
view.autocapitalizationType = .none
|
||||
@@ -24,6 +45,7 @@ struct SyntaxCodeEditor: UIViewRepresentable {
|
||||
view.accessibilityIdentifier = "syntaxCodeEditor"
|
||||
if #available(iOS 16.0, *) { view.isFindInteractionEnabled = true }
|
||||
let bar = UIToolbar()
|
||||
bar.tintColor = UIColor(ReadingTheme.accent)
|
||||
bar.sizeToFit()
|
||||
bar.items = [
|
||||
UIBarButtonItem(image: UIImage(systemName: "magnifyingglass"), primaryAction: UIAction(title: "", subtitle: nil) { [weak view, coordinator = context.coordinator] _ in
|
||||
@@ -126,12 +148,12 @@ struct SyntaxCodeEditor: UIViewRepresentable {
|
||||
storage.addAttributes([.font: UIFont.monospacedSystemFont(ofSize: 14, weight: .regular), .foregroundColor: UIColor.label], range: all)
|
||||
if storage.length <= 500_000 {
|
||||
let tokens: [(String, UIColor)] = [
|
||||
(#"\b(?:true|false|null|undefined|return|var|let|const|if|else|function|new|for|while|try|catch|throw|await|async)\b"#, .systemPurple),
|
||||
(#"\b\d+(?:\.\d+)?\b"#, .systemOrange),
|
||||
(#"@(?:css|xpath|json|js|put|get):?|\$\.|&&|\|\||%%|##|\{\{|\}\}"#, .systemPink),
|
||||
(#"[{}\[\]()]"#, .systemTeal),
|
||||
(#""(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|`(?:\\.|[^`\\])*`"#, .systemGreen),
|
||||
(#""(?:\\.|[^"\\])*"(?=\s*:)"#, .systemBlue),
|
||||
(#"\b(?:true|false|null|undefined|return|var|let|const|if|else|function|new|for|while|try|catch|throw|await|async)\b"#, Palette.keyword),
|
||||
(#"\b\d+(?:\.\d+)?\b"#, Palette.number),
|
||||
(#"@(?:css|xpath|json|js|put|get):?|\$\.|&&|\|\||%%|##|\{\{|\}\}"#, Palette.operation),
|
||||
(#"[{}\[\]()]"#, Palette.punctuation),
|
||||
(#""(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|`(?:\\.|[^`\\])*`"#, Palette.string),
|
||||
(#""(?:\\.|[^"\\])*"(?=\s*:)"#, Palette.key),
|
||||
]
|
||||
for (pattern, color) in tokens {
|
||||
guard let regex = try? NSRegularExpression(pattern: pattern) else { continue }
|
||||
@@ -143,7 +165,7 @@ struct SyntaxCodeEditor: UIViewRepresentable {
|
||||
for pattern in [#"[.*+?^$|]"#, #"\\[dDsSwWbB0-9]|\{[0-9,]+\}"#] {
|
||||
let regex = try? NSRegularExpression(pattern: pattern)
|
||||
regex?.enumerateMatches(in: view.text, range: all) { result, _, _ in
|
||||
if let result { storage.addAttribute(.foregroundColor, value: UIColor.systemPink, range: result.range) }
|
||||
if let result { storage.addAttribute(.foregroundColor, value: Palette.operation, range: result.range) }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -151,7 +173,7 @@ struct SyntaxCodeEditor: UIViewRepresentable {
|
||||
let pattern = #"(?m)^\s*//.*$|/\*[\s\S]*?\*/"#
|
||||
let regex = try? NSRegularExpression(pattern: pattern)
|
||||
regex?.enumerateMatches(in: view.text, range: all) { result, _, _ in
|
||||
if let result { storage.addAttribute(.foregroundColor, value: UIColor.secondaryLabel, range: result.range) }
|
||||
if let result { storage.addAttribute(.foregroundColor, value: Palette.comment, range: result.range) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,8 +81,7 @@ struct SourceDebugView: View {
|
||||
Label(model.isRunning ? "正在调试…" : "运行完整链路", systemImage: "play.fill")
|
||||
.font(.headline).frame(maxWidth: .infinity)
|
||||
}
|
||||
.buttonStyle(.borderedProminent)
|
||||
.tint(ReadingTheme.accent)
|
||||
.readingProminentButtonStyle()
|
||||
.disabled(model.isRunning || model.keyword.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,11 +44,10 @@ struct SourceEditorView: View {
|
||||
HStack {
|
||||
ForEach(BookSourceEditorSchema.sections) { section in
|
||||
Button(section.title) { sectionID = section.id }
|
||||
.buttonStyle(.bordered)
|
||||
.tint(sectionID == section.id ? ReadingTheme.accent : .secondary)
|
||||
.readingChoiceButtonStyle(isSelected: sectionID == section.id)
|
||||
}
|
||||
Button("选项") { sectionID = "options" }.buttonStyle(.bordered)
|
||||
.tint(sectionID == "options" ? ReadingTheme.accent : .secondary)
|
||||
Button("选项") { sectionID = "options" }
|
||||
.readingChoiceButtonStyle(isSelected: sectionID == "options")
|
||||
}.padding(.horizontal)
|
||||
}.padding(.vertical, 6)
|
||||
Form {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
@preconcurrency import WebKit
|
||||
import SwiftUI
|
||||
import UIKit
|
||||
|
||||
struct SourceLoginView: View {
|
||||
let source: BookSource
|
||||
@@ -74,6 +75,9 @@ private struct SourceLoginWebView: UIViewRepresentable {
|
||||
let configuration = WKWebViewConfiguration()
|
||||
configuration.websiteDataStore = .default()
|
||||
let webView = WKWebView(frame: .zero, configuration: configuration)
|
||||
webView.isOpaque = false
|
||||
webView.backgroundColor = UIColor(ReadingTheme.canvas)
|
||||
webView.scrollView.backgroundColor = UIColor(ReadingTheme.canvas)
|
||||
webView.navigationDelegate = context.coordinator
|
||||
context.coordinator.installExistingCookies(in: webView) { webView.load(request) }
|
||||
return webView
|
||||
|
||||
@@ -61,7 +61,7 @@ struct SourceManagementView: View {
|
||||
Text("新建书源,或从文件、链接、JSON、二维码导入。")
|
||||
} actions: {
|
||||
Button("导入书源", action: presentFileImporter)
|
||||
.buttonStyle(.borderedProminent)
|
||||
.readingProminentButtonStyle()
|
||||
}
|
||||
} else {
|
||||
List {
|
||||
|
||||
+14
-9
@@ -50,6 +50,10 @@ struct RootTabView: View {
|
||||
SearchView(initialKeyword: automationSearchKeyword)
|
||||
} else if requestedDemoPage == "sources" {
|
||||
SourceManagementView()
|
||||
} else if requestedDemoPage == "rss" {
|
||||
RSSHomeView()
|
||||
} else if requestedDemoPage == "rss-photo" {
|
||||
RSSPhotoView(value: "data:image/png;base64,", source: RssSource(sourceUrl: "https://appearance.invalid", sourceName: "图片外观检查"))
|
||||
} else {
|
||||
BookshelfView()
|
||||
}
|
||||
@@ -99,7 +103,6 @@ struct RootTabView: View {
|
||||
.tabItem { Label("我的", systemImage: "person.crop.circle") }
|
||||
.tag(Tab.my)
|
||||
}
|
||||
.tint(ReadingTheme.accent)
|
||||
.readingTabBarBackground()
|
||||
.preferredColorScheme(themeMode == "2" ? .dark : (themeMode == "1" || themeMode == "3" ? .light : nil))
|
||||
.transaction { transaction in
|
||||
@@ -123,6 +126,8 @@ struct RootTabView: View {
|
||||
dismissButton: .default(Text("好")) { sourceLibrary.notice = nil }
|
||||
)
|
||||
}
|
||||
.tint(ReadingTheme.accent)
|
||||
.toggleStyle(SwitchToggleStyle(tint: ReadingTheme.toggleTint))
|
||||
}
|
||||
|
||||
private var requestedDemoPage: String? {
|
||||
@@ -487,7 +492,7 @@ private struct ContinueReadingCard: View {
|
||||
.foregroundStyle(ReadingTheme.onAccent)
|
||||
.padding(.horizontal, 18)
|
||||
.frame(minHeight: 40)
|
||||
.background(ReadingTheme.accent, in: Capsule())
|
||||
.background(ReadingTheme.accentFill, in: Capsule())
|
||||
.padding(.top, 20)
|
||||
}
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
@@ -719,7 +724,7 @@ private struct EmptyBookshelfHero: View {
|
||||
}
|
||||
VStack(spacing: 12) {
|
||||
Button("导入本地书", action: onImport)
|
||||
.buttonStyle(.borderedProminent)
|
||||
.readingProminentButtonStyle()
|
||||
.controlSize(.large)
|
||||
NavigationLink("添加书源") { SourceManagementView() }
|
||||
.font(.subheadline)
|
||||
@@ -986,7 +991,7 @@ struct SearchView: View {
|
||||
Spacer()
|
||||
if model.isPaused {
|
||||
Button("继续", systemImage: "play.fill") { model.resume() }
|
||||
.buttonStyle(.bordered)
|
||||
.readingSecondaryButtonStyle()
|
||||
.controlSize(.small)
|
||||
} else if model.state == .searching {
|
||||
StatusPill(text: "\(model.completedSourceCount)/\(model.totalSourceCount)", systemImage: "magnifyingglass")
|
||||
@@ -1037,10 +1042,10 @@ struct SearchView: View {
|
||||
) {
|
||||
if model.isPaused {
|
||||
Button("继续搜索", systemImage: "play.fill") { model.resume() }
|
||||
.buttonStyle(.borderedProminent).tint(ReadingTheme.accent)
|
||||
.readingProminentButtonStyle()
|
||||
}
|
||||
Button("修改关键词", systemImage: "text.cursor") { searchIsPresented = true }
|
||||
.buttonStyle(.bordered)
|
||||
.readingSecondaryButtonStyle()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1051,13 +1056,13 @@ struct SearchView: View {
|
||||
systemImage: "network.slash"
|
||||
) {
|
||||
Button("调整范围", systemImage: "scope") { showsScope = true }
|
||||
.buttonStyle(.borderedProminent).tint(ReadingTheme.accent)
|
||||
.readingProminentButtonStyle()
|
||||
NavigationLink {
|
||||
SourceManagementView()
|
||||
} label: {
|
||||
Label("管理书源", systemImage: "network")
|
||||
}
|
||||
.buttonStyle(.bordered)
|
||||
.readingSecondaryButtonStyle()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1281,7 +1286,7 @@ private struct SettingsView: View {
|
||||
.clipped()
|
||||
.overlay {
|
||||
if colorScheme == .dark {
|
||||
Color.black.opacity(0.62)
|
||||
Color.black.opacity(0.78)
|
||||
}
|
||||
}
|
||||
.overlay(alignment: .bottom) {
|
||||
|
||||
Reference in New Issue
Block a user