Initial Create
基础框架实现
This commit is contained in:
130
Jetson Media/ui/PhotoView.swift
Normal file
130
Jetson Media/ui/PhotoView.swift
Normal file
@@ -0,0 +1,130 @@
|
||||
import SwiftUI
|
||||
import Combine
|
||||
|
||||
struct PhotoView: View {
|
||||
let albumId: String
|
||||
@StateObject private var viewModel: PhotoViewModel
|
||||
|
||||
init(albumId: String) {
|
||||
self.albumId = albumId
|
||||
self._viewModel = StateObject(wrappedValue: PhotoViewModel(albumId: albumId))
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
if viewModel.isLoading {
|
||||
ProgressView()
|
||||
} else if let album = viewModel.album {
|
||||
ScrollView {
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
Text(album.name)
|
||||
.font(.headline)
|
||||
|
||||
Text("作者: \(album.authors.joined(separator: ", "))")
|
||||
.font(.subheadline)
|
||||
|
||||
Text("标签: \(album.tags.joined(separator: ", "))")
|
||||
.font(.caption)
|
||||
.foregroundColor(.gray)
|
||||
}
|
||||
.padding()
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.background(Color(.systemBackground))
|
||||
|
||||
LazyVStack(spacing: 0) { // 去掉图片间距
|
||||
ForEach(Array(album.image_urls.enumerated()), id: \.offset) { index, url in
|
||||
AsyncImageView(
|
||||
url: url,
|
||||
nums: album.nums,
|
||||
index: index
|
||||
)
|
||||
.frame(maxWidth: .infinity) // 强制图片填充父视图宽度
|
||||
.aspectRatio(contentMode: .fill) // 确保图片填充整个区域
|
||||
.clipped() // 防止图片超出边界
|
||||
}
|
||||
}
|
||||
}
|
||||
.edgesIgnoringSafeArea(.all) // 让内容填充整个屏幕
|
||||
} else if let error = viewModel.error {
|
||||
Text("加载失败: \(error.localizedDescription)")
|
||||
}
|
||||
}
|
||||
.alert(isPresented: $viewModel.showAlert) {
|
||||
Alert(
|
||||
title: Text(viewModel.alertTitle),
|
||||
message: Text(viewModel.alertMessage),
|
||||
dismissButton: .default(Text("确定"))
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
// 其余代码保持不变(PhotoView, PhotoViewModel, Album结构体等)
|
||||
class PhotoViewModel: ObservableObject {
|
||||
let albumId: String
|
||||
|
||||
@Published var album: Album?
|
||||
@Published var isLoading = false
|
||||
@Published var error: Error?
|
||||
@Published var scrollPosition: Double = 0
|
||||
@Published var showAlert = false
|
||||
@Published var alertTitle = ""
|
||||
@Published var alertMessage = ""
|
||||
|
||||
private var cancellables = Set<AnyCancellable>()
|
||||
|
||||
init(albumId: String) {
|
||||
self.albumId = albumId
|
||||
loadAlbumData()
|
||||
}
|
||||
|
||||
func loadAlbumData() {
|
||||
isLoading = true
|
||||
error = nil
|
||||
|
||||
let urlString = "https://jms.godserver.cn/album/\(albumId)/"
|
||||
guard let url = URL(string: urlString) else {
|
||||
error = NSError(domain: "无效的URL", code: 0, userInfo: nil)
|
||||
isLoading = false
|
||||
return
|
||||
}
|
||||
|
||||
print("正在加载相册数据: \(urlString)")
|
||||
|
||||
URLSession.shared.dataTaskPublisher(for: url)
|
||||
.map(\.data)
|
||||
.decode(type: Album.self, decoder: JSONDecoder())
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink(receiveCompletion: { [weak self] completion in
|
||||
self?.isLoading = false
|
||||
if case .failure(let error) = completion {
|
||||
self?.error = error
|
||||
print("相册加载失败: \(error.localizedDescription)")
|
||||
}
|
||||
}, receiveValue: { [weak self] album in
|
||||
self?.album = album
|
||||
print("成功加载相册: \(album.name), 包含 \(album.image_urls.count) 张图片")
|
||||
})
|
||||
.store(in: &cancellables)
|
||||
}
|
||||
|
||||
func showAlert(title: String, message: String) {
|
||||
alertTitle = title
|
||||
alertMessage = message
|
||||
showAlert = true
|
||||
}
|
||||
}
|
||||
struct Album: Codable {
|
||||
let album_id: String
|
||||
let name: String
|
||||
let authors: [String]
|
||||
let actors: [String]
|
||||
let tags: [String]
|
||||
let image_urls: [String]
|
||||
let nums: [Int]
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case album_id, name, authors, actors, tags
|
||||
case image_urls = "image_urls"
|
||||
case nums
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user