2025-03-03 23:00:57 +08:00

171 lines
5.8 KiB
Swift

//
// ListView.swift
// dimensionhub
//
// Created by on 2025/2/21.
//
import SwiftUI
import Observation
@Observable
final class ListModel {
struct Episode: Codable, Identifiable {
let id = UUID().uuidString
let name: String
let num_name: String
let thumb: String
let play: String
enum CodingKeys: String, CodingKey {
case name, num_name, thumb, play
}
}
//
struct Channel: Codable {
let name: String
let episodes: [Episode]
}
struct DramaDetailResponse: Codable {
let name: String
let summary: String
let thumb: String
let status: [String]
let channels: [Channel]
}
var name: String = ""
var summary: String = ""
var thumb: String = ""
var channels: [Channel] = []
// channel
var selectedChannelIdx: Int = 0
var selectedEpisodes: [Episode] = []
@MainActor
func loadData(userId: String, id: Int) async {
let response = await API.getDramaDetail(userId: userId, id: id, as: DramaDetailResponse.self)
switch response {
case .error(let code, let message):
print(code)
print(message)
case .result(let detail):
self.name = detail.name
self.summary = Utils.converHtmlToString(html: detail.summary) ?? ""
self.thumb = detail.thumb
self.channels = detail.channels
self.selectedChannelIdx = 0
self.selectedEpisodes = detail.channels[0].episodes
}
}
func toggleChannel(channelIdx: Int) {
self.selectedChannelIdx = channelIdx
self.selectedEpisodes = self.channels[channelIdx].episodes
}
}
struct ListView: View {
@Environment(\.presentationMode) var presentationMode
@AppStorage("userId") private var userId: String = Utils.defaultUserId()
@State var detailModel = ListModel()
let id: Int
var body: some View {
VStack(alignment: .center, spacing: 20) {
HStack {
VStack(alignment: .leading, spacing: 20) {
Text(detailModel.name)
.font(.system(size: 28))
.foregroundColor(Color(hex: "#333333"))
.fontWeight(.medium)
}
Spacer()
}
.padding([.leading, .top, .bottom], 10)
.background(Color(hex: "#F2F2F2"), ignoresSafeAreaEdges: [.top])
VStack {
//
HStack(alignment: .center, spacing: 15) {
ForEach(Array(detailModel.channels.enumerated()), id: \.offset) { idx, channel in
Text(channel.name)
.font(.system(size: 13))
.foregroundColor(idx == detailModel.selectedChannelIdx ? Color(hex: "#169BD5") : Color(hex: "#666666"))
.onTapGesture {
detailModel.toggleChannel(channelIdx: idx)
}
}
Spacer()
}
//
ScrollView(.vertical, showsIndicators: false) {
LazyVStack(alignment: .center, spacing: 15) {
ForEach(detailModel.selectedEpisodes) { episode in
HStack(alignment: .center) {
AsyncImage(url: URL(string: episode.thumb)) { image in
image.resizable()
} placeholder: {
ProgressView()
}
.frame(width: 90, height: 60)
VStack(alignment: .leading, spacing: 20) {
Text(episode.num_name)
.font(.system(size: 12))
.foregroundColor(Color(hex: "#333333"))
Text(episode.name)
.font(.system(size: 12))
.foregroundColor(Color(hex: "#333333"))
.lineLimit(1)
}
Spacer()
}
.onTapGesture {
if let playUrl = URL(string: episode.play) {
UIApplication.shared.open(playUrl)
}
}
}
}
}
HStack(alignment: .center) {
Button {
self.presentationMode.wrappedValue.dismiss()
} label: {
Rectangle()
.frame(width: 200, height: 25)
.foregroundColor(Color(hex: "#F2F2F2"))
.overlay {
Text("收起剧集")
.font(.system(size: 13))
.foregroundColor(Color(hex: "#999999"))
}
}
}
Spacer()
}
.frame(width: 370, alignment: .center)
}
.task {
await detailModel.loadData(userId: self.userId, id: self.id)
}
}
}
#Preview {
ListView(id: 19625)
}