mirror of
https://github.com/Aminark/legado-ios.git
synced 2026-10-24 12:51:22 +08:00
支持 EPUB 2/3 导入、目录、封面和章节插图,保留本地书管理与阅读进度。 修复 JSON 模板、动态替换与请求参数兼容,以及 RSS 翻页和连续滚动定位。 更新编辑器工具栏和回归测试,发布版本为 0.1.12(build 18)。
75 lines
3.1 KiB
Swift
75 lines
3.1 KiB
Swift
import SwiftUI
|
|
import ImageIO
|
|
|
|
struct EPUBIllustrationsView: View {
|
|
@Environment(\.dismiss) private var dismiss
|
|
let book: Book
|
|
let chapter: BookChapter
|
|
@State private var images: [EPUBIllustration] = []
|
|
@State private var isLoading = true
|
|
@State private var errorMessage: String?
|
|
|
|
var body: some View {
|
|
ReadingNavigationStack {
|
|
ScrollView {
|
|
LazyVStack(spacing: 24) {
|
|
if isLoading {
|
|
ProgressView("正在读取插图…").padding()
|
|
} else if let errorMessage {
|
|
ReadingUnavailableView("无法读取插图", systemImage: "photo", description: Text(errorMessage))
|
|
} else if images.isEmpty {
|
|
ReadingUnavailableView("本章没有插图", systemImage: "photo", description: Text(chapter.title))
|
|
} else {
|
|
ForEach(images) { image in
|
|
VStack(spacing: 8) {
|
|
EPUBIllustrationImage(data: image.data)
|
|
Text("插图 \(image.id)\(image.caption.isEmpty ? "" : " · " + image.caption)")
|
|
.font(.caption).foregroundStyle(.secondary)
|
|
}
|
|
}
|
|
}
|
|
}.padding()
|
|
}
|
|
.background(ReadingTheme.canvas)
|
|
.navigationTitle("本章插图")
|
|
.navigationBarTitleDisplayMode(.inline)
|
|
.toolbar { ToolbarItem(placement: .confirmationAction) { Button("完成") { dismiss() } } }
|
|
.task(id: chapter.id) {
|
|
isLoading = true
|
|
errorMessage = nil
|
|
do {
|
|
images = try await Task.detached { try LocalBookService().loadIllustrations(book: book, chapter: chapter) }.value
|
|
} catch { errorMessage = error.localizedDescription }
|
|
isLoading = false
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private struct EPUBIllustrationImage: View {
|
|
let data: Data
|
|
@State private var image: UIImage?
|
|
|
|
var body: some View {
|
|
Group {
|
|
if let image {
|
|
Image(uiImage: image).resizable().scaledToFit().accessibilityLabel("书籍插图")
|
|
} else {
|
|
Text("图片无法显示").foregroundStyle(.secondary)
|
|
}
|
|
}
|
|
.task {
|
|
// Decode a bounded thumbnail off the main thread, even for huge source dimensions.
|
|
image = await Task.detached {
|
|
guard let source = CGImageSourceCreateWithData(data as CFData, nil),
|
|
let thumbnail = CGImageSourceCreateThumbnailAtIndex(source, 0, [
|
|
kCGImageSourceCreateThumbnailFromImageAlways: true,
|
|
kCGImageSourceThumbnailMaxPixelSize: 2_048,
|
|
kCGImageSourceCreateThumbnailWithTransform: true
|
|
] as CFDictionary) else { return Optional<UIImage>.none }
|
|
return UIImage(cgImage: thumbnail)
|
|
}.value
|
|
}
|
|
}
|
|
}
|