mirror of
https://github.com/Aminark/legado-ios.git
synced 2026-10-20 19:21:22 +08:00
93 lines
5.4 KiB
Swift
93 lines
5.4 KiB
Swift
import SwiftUI
|
||
|
||
struct RSSSourceEditorView: View {
|
||
@EnvironmentObject private var library: RSSLibraryModel
|
||
@Environment(\.dismiss) private var dismiss
|
||
@State private var source: RssSource
|
||
private let originalURL: String?
|
||
|
||
init(source: RssSource? = nil) {
|
||
let value = source ?? RssSource()
|
||
_source = State(initialValue: value)
|
||
originalURL = source?.sourceUrl
|
||
}
|
||
|
||
var body: some View {
|
||
Form {
|
||
Section("基本") {
|
||
TextField("名称", text: $source.sourceName)
|
||
TextField("URL", text: $source.sourceUrl).textInputAutocapitalization(.never).keyboardType(.URL)
|
||
requiredField("图标", \.sourceIcon)
|
||
optionalField("分组", \.sourceGroup)
|
||
optionalField("注释", \.sourceComment, axis: .vertical)
|
||
Toggle("启用", isOn: $source.enabled)
|
||
}
|
||
Section("请求与登录") {
|
||
optionalField("自定义变量说明", \.variableComment, axis: .vertical)
|
||
optionalField("JS库", \.jsLib, axis: .vertical)
|
||
Toggle("自动保存Cookie", isOn: optionalBool(\.enabledCookieJar, default: true))
|
||
optionalField("并发率", \.concurrentRate)
|
||
optionalField("请求头", \.header, axis: .vertical)
|
||
optionalField("登录地址", \.loginUrl)
|
||
optionalField("登录UI", \.loginUi, axis: .vertical)
|
||
optionalField("登录检测JS", \.loginCheckJs, axis: .vertical)
|
||
optionalField("封面解密JS", \.coverDecodeJs, axis: .vertical)
|
||
}
|
||
Section("分类与列表规则") {
|
||
optionalField("分类URL(名称::URL)", \.sortUrl, axis: .vertical)
|
||
Toggle("单URL源", isOn: $source.singleUrl)
|
||
Picker("列表样式", selection: $source.articleStyle) { ForEach(0..<5, id: \.self) { Text("样式 \($0)").tag($0) } }
|
||
optionalField("列表规则", \.ruleArticles, axis: .vertical)
|
||
optionalField("下一页规则", \.ruleNextPage, axis: .vertical)
|
||
optionalField("标题规则", \.ruleTitle, axis: .vertical)
|
||
optionalField("发布日期规则", \.rulePubDate, axis: .vertical)
|
||
optionalField("描述规则", \.ruleDescription, axis: .vertical)
|
||
optionalField("图片规则", \.ruleImage, axis: .vertical)
|
||
optionalField("链接规则", \.ruleLink, axis: .vertical)
|
||
optionalField("正文规则", \.ruleContent, axis: .vertical)
|
||
}
|
||
Section("WebView规则") {
|
||
optionalField("正文URL白名单", \.contentWhitelist, axis: .vertical)
|
||
optionalField("正文URL黑名单", \.contentBlacklist, axis: .vertical)
|
||
optionalField("跳转URL拦截JS", \.shouldOverrideUrlLoading, axis: .vertical)
|
||
optionalField("样式", \.style, axis: .vertical)
|
||
Toggle("启用JavaScript", isOn: $source.enableJs)
|
||
Toggle("使用Base URL加载", isOn: $source.loadWithBaseUrl)
|
||
optionalField("注入JS", \.injectJs, axis: .vertical)
|
||
optionalField("预注入JS", \.preloadJs, axis: .vertical)
|
||
optionalField("起始HTML", \.startHtml, axis: .vertical)
|
||
optionalField("起始样式", \.startStyle, axis: .vertical)
|
||
optionalField("起始JS", \.startJs, axis: .vertical)
|
||
Toggle("输出网页日志", isOn: $source.showWebLog)
|
||
}
|
||
Section("其他") {
|
||
Stepper("自定义排序:\(source.customOrder)", value: $source.customOrder)
|
||
Picker("类型", selection: $source.type) { Text("网页").tag(0); Text("图片").tag(1); Text("视频").tag(2) }
|
||
Toggle("启用预加载", isOn: $source.preload)
|
||
Toggle("优先加载缓存", isOn: $source.cacheFirst)
|
||
optionalField("搜索URL", \.searchUrl, axis: .vertical)
|
||
}
|
||
}
|
||
.navigationTitle(originalURL == nil ? "新建RSS源" : "编辑RSS源")
|
||
.navigationBarTitleDisplayMode(.inline)
|
||
.toolbar {
|
||
ToolbarItem(placement: .confirmationAction) {
|
||
Button("保存") { Task { if await library.save(source, replacing: originalURL) { dismiss() } } }
|
||
}
|
||
}
|
||
}
|
||
|
||
@ViewBuilder private func optionalField(_ title: String, _ keyPath: WritableKeyPath<RssSource, String?>, axis: Axis = .horizontal) -> some View {
|
||
ReadingTextField(title, text: optionalText(keyPath), axis: axis).textInputAutocapitalization(.never)
|
||
}
|
||
@ViewBuilder private func requiredField(_ title: String, _ keyPath: WritableKeyPath<RssSource, String>, axis: Axis = .horizontal) -> some View {
|
||
ReadingTextField(title, text: Binding(get: { source[keyPath: keyPath] }, set: { source[keyPath: keyPath] = $0 }), axis: axis).textInputAutocapitalization(.never)
|
||
}
|
||
private func optionalText(_ keyPath: WritableKeyPath<RssSource, String?>) -> Binding<String> {
|
||
Binding(get: { source[keyPath: keyPath] ?? "" }, set: { source[keyPath: keyPath] = $0.isEmpty ? nil : $0 })
|
||
}
|
||
private func optionalBool(_ keyPath: WritableKeyPath<RssSource, Bool?>, default defaultValue: Bool) -> Binding<Bool> {
|
||
Binding(get: { source[keyPath: keyPath] ?? defaultValue }, set: { source[keyPath: keyPath] = $0 })
|
||
}
|
||
}
|