fix view
This commit is contained in:
parent
7468710008
commit
cac31802b3
53
dimensionhub/Views/FollowList/FollowListModel.swift
Normal file
53
dimensionhub/Views/FollowList/FollowListModel.swift
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
//
|
||||||
|
// FollowListModel.swift
|
||||||
|
// dimensionhub
|
||||||
|
//
|
||||||
|
// Created by 安礼成 on 2025/4/8.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import Observation
|
||||||
|
|
||||||
|
@Observable
|
||||||
|
final class FollowListModel {
|
||||||
|
|
||||||
|
struct DramaItem: Codable {
|
||||||
|
struct Episode: Codable, Identifiable {
|
||||||
|
let id = UUID().uuidString
|
||||||
|
let name: String
|
||||||
|
let thumb: String
|
||||||
|
let num_name: String
|
||||||
|
let play: String
|
||||||
|
|
||||||
|
enum CodingKeys: String, CodingKey {
|
||||||
|
case name, thumb, num_name, play
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let id: Int
|
||||||
|
let title: String
|
||||||
|
let episodes: [Episode]
|
||||||
|
}
|
||||||
|
|
||||||
|
struct FavorResponse: Codable {
|
||||||
|
let dramas: [DramaItem]
|
||||||
|
}
|
||||||
|
|
||||||
|
var dramas: [DramaItem]
|
||||||
|
|
||||||
|
init() {
|
||||||
|
self.dramas = []
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadData(userId: String) async {
|
||||||
|
let response = await API.getUserFollowList(userId: userId, as: FavorResponse.self)
|
||||||
|
switch response {
|
||||||
|
case .error(let code, let message):
|
||||||
|
print("index load data get error_code: \(code), message: \(message)")
|
||||||
|
case .result(let result):
|
||||||
|
await MainActor.run {
|
||||||
|
self.dramas = result.dramas
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
144
dimensionhub/Views/FollowList/FollowListView.swift
Normal file
144
dimensionhub/Views/FollowList/FollowListView.swift
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
//
|
||||||
|
// FavorView.swift
|
||||||
|
// dimensionhub
|
||||||
|
//
|
||||||
|
// Created by 安礼成 on 2025/3/18.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct FollowListView: View {
|
||||||
|
@AppStorage("userId") private var userId: String = Utils.defaultUserId()
|
||||||
|
@State var followModel = FollowListModel()
|
||||||
|
@State var isMoreLoading: Bool = false
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
VStack(alignment: .center) {
|
||||||
|
Rectangle()
|
||||||
|
.frame(height: 0)
|
||||||
|
.background(Color(hex: "#F2F2F2"), ignoresSafeAreaEdges: .top)
|
||||||
|
.border(.red)
|
||||||
|
|
||||||
|
Group {
|
||||||
|
if followModel.dramas.count > 0 {
|
||||||
|
ScrollView(.vertical, showsIndicators: false) {
|
||||||
|
LazyVStack(alignment: .center) {
|
||||||
|
ForEach(followModel.dramas, id: \.id) { drama in
|
||||||
|
DramaCellView(dramaItem: drama)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
VStack {
|
||||||
|
Spacer()
|
||||||
|
Text("这里什么都没有")
|
||||||
|
.font(.system(size: 16))
|
||||||
|
.foregroundColor(.black)
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.frame(width: 370)
|
||||||
|
}
|
||||||
|
.ignoresSafeArea(edges: .bottom)
|
||||||
|
.navigationTitle("番剧补完计划")
|
||||||
|
.task {
|
||||||
|
await self.followModel.loadData(userId: self.userId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension FollowListView {
|
||||||
|
|
||||||
|
// 显示剧集的列表信息
|
||||||
|
struct DramaCellView: View {
|
||||||
|
let dramaItem: FollowListModel.DramaItem
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
VStack(alignment: .leading) {
|
||||||
|
|
||||||
|
NavigationLink(destination: DetailView(id: dramaItem.id)) {
|
||||||
|
Text(dramaItem.title)
|
||||||
|
.font(.system(size: 20))
|
||||||
|
.foregroundColor(Color(hex: "#333333"))
|
||||||
|
.lineLimit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
ScrollView(.horizontal, showsIndicators: false) {
|
||||||
|
LazyHStack(alignment: .center, spacing: 5) {
|
||||||
|
ForEach(dramaItem.episodes) { item in
|
||||||
|
DramaCellEpisodeView(item: item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct DramaCellEpisodeView: View {
|
||||||
|
let item: FollowListModel.DramaItem.Episode
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
VStack(alignment: .center) {
|
||||||
|
GeometryReader { geometry in
|
||||||
|
|
||||||
|
AsyncImage(url: URL(string: item.thumb)) { phase in
|
||||||
|
switch phase {
|
||||||
|
case .empty:
|
||||||
|
ProgressView()
|
||||||
|
case .success(let image):
|
||||||
|
image
|
||||||
|
.resizable()
|
||||||
|
.aspectRatio(contentMode: .fill)
|
||||||
|
.frame(width: geometry.frame(in: .local).width, height: 80)
|
||||||
|
.clipped()
|
||||||
|
default:
|
||||||
|
Image("ph_img_medium")
|
||||||
|
.resizable()
|
||||||
|
.aspectRatio(contentMode: .fill)
|
||||||
|
.frame(width: geometry.frame(in: .local).width, height: 80)
|
||||||
|
.clipped()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.frame(width: geometry.frame(in: .local).width, height: 80)
|
||||||
|
.overlay(alignment: .topLeading) {
|
||||||
|
if !item.num_name.isEmpty {
|
||||||
|
HStack(alignment: .center) {
|
||||||
|
Text(item.num_name)
|
||||||
|
.font(.system(size: 12))
|
||||||
|
.foregroundColor(.white)
|
||||||
|
.lineLimit(1)
|
||||||
|
}
|
||||||
|
.padding(3)
|
||||||
|
.background(
|
||||||
|
Color.black.opacity(0.6)
|
||||||
|
)
|
||||||
|
.cornerRadius(3)
|
||||||
|
.padding(3)
|
||||||
|
} else {
|
||||||
|
EmptyView()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Text(item.name)
|
||||||
|
.font(.system(size: 12))
|
||||||
|
.foregroundColor(Color(hex: "#333333"))
|
||||||
|
.lineLimit(1)
|
||||||
|
}
|
||||||
|
.frame(width: 120, height: 100)
|
||||||
|
.onTapGesture {
|
||||||
|
if let playUrl = URL(string: item.play) {
|
||||||
|
UIApplication.shared.open(playUrl)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#Preview {
|
||||||
|
FollowListView()
|
||||||
|
}
|
||||||
@ -1,179 +0,0 @@
|
|||||||
//
|
|
||||||
// FavorView.swift
|
|
||||||
// dimensionhub
|
|
||||||
//
|
|
||||||
// Created by 安礼成 on 2025/3/18.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import SwiftUI
|
|
||||||
import Observation
|
|
||||||
|
|
||||||
@Observable
|
|
||||||
final class FollowListModel {
|
|
||||||
|
|
||||||
struct DramaItem: Codable {
|
|
||||||
struct Episode: Codable, Identifiable {
|
|
||||||
let id = UUID().uuidString
|
|
||||||
let name: String
|
|
||||||
let thumb: String
|
|
||||||
let num_name: String
|
|
||||||
let play: String
|
|
||||||
|
|
||||||
enum CodingKeys: String, CodingKey {
|
|
||||||
case name, thumb, num_name, play
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let id: Int
|
|
||||||
let title: String
|
|
||||||
let episodes: [Episode]
|
|
||||||
}
|
|
||||||
|
|
||||||
struct FavorResponse: Codable {
|
|
||||||
let dramas: [DramaItem]
|
|
||||||
}
|
|
||||||
|
|
||||||
var dramas: [DramaItem]
|
|
||||||
|
|
||||||
init() {
|
|
||||||
self.dramas = []
|
|
||||||
}
|
|
||||||
|
|
||||||
func loadData(userId: String) async {
|
|
||||||
let response = await API.getUserFollowList(userId: userId, as: FavorResponse.self)
|
|
||||||
switch response {
|
|
||||||
case .error(let code, let message):
|
|
||||||
print("index load data get error_code: \(code), message: \(message)")
|
|
||||||
case .result(let result):
|
|
||||||
await MainActor.run {
|
|
||||||
self.dramas = result.dramas
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct FollowListView: View {
|
|
||||||
@AppStorage("userId") private var userId: String = Utils.defaultUserId()
|
|
||||||
@State var followModel = FollowListModel()
|
|
||||||
@State var isMoreLoading: Bool = false
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
VStack(alignment: .center) {
|
|
||||||
Rectangle()
|
|
||||||
.frame(height: 0)
|
|
||||||
.background(Color(hex: "#F2F2F2"), ignoresSafeAreaEdges: .top)
|
|
||||||
.border(.red)
|
|
||||||
|
|
||||||
Group {
|
|
||||||
if followModel.dramas.count > 0 {
|
|
||||||
ScrollView(.vertical, showsIndicators: false) {
|
|
||||||
LazyVStack(alignment: .center) {
|
|
||||||
ForEach(followModel.dramas, id: \.id) { drama in
|
|
||||||
DramaCellView(dramaItem: drama)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
VStack {
|
|
||||||
Spacer()
|
|
||||||
Text("这里什么都没有")
|
|
||||||
.font(.system(size: 16))
|
|
||||||
.foregroundColor(.black)
|
|
||||||
Spacer()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.frame(width: 370)
|
|
||||||
}
|
|
||||||
.ignoresSafeArea(edges: .bottom)
|
|
||||||
.navigationTitle("番剧补完计划")
|
|
||||||
.task {
|
|
||||||
await self.followModel.loadData(userId: self.userId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
extension FollowListView {
|
|
||||||
// 显示剧集的列表信息
|
|
||||||
struct DramaCellView: View {
|
|
||||||
let dramaItem: FollowListModel.DramaItem
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
VStack(alignment: .leading) {
|
|
||||||
|
|
||||||
NavigationLink(destination: DetailView(id: dramaItem.id)) {
|
|
||||||
Text(dramaItem.title)
|
|
||||||
.font(.system(size: 20))
|
|
||||||
.foregroundColor(Color(hex: "#333333"))
|
|
||||||
.lineLimit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
ScrollView(.horizontal, showsIndicators: false) {
|
|
||||||
LazyHStack(alignment: .center, spacing: 5) {
|
|
||||||
ForEach(dramaItem.episodes) { item in
|
|
||||||
VStack(alignment: .center) {
|
|
||||||
GeometryReader { geometry in
|
|
||||||
|
|
||||||
AsyncImage(url: URL(string: item.thumb)) { phase in
|
|
||||||
switch phase {
|
|
||||||
case .empty:
|
|
||||||
ProgressView()
|
|
||||||
case .success(let image):
|
|
||||||
image
|
|
||||||
.resizable()
|
|
||||||
.aspectRatio(contentMode: .fill)
|
|
||||||
.frame(width: geometry.frame(in: .local).width, height: 80)
|
|
||||||
.clipped()
|
|
||||||
default:
|
|
||||||
Image("ph_img_medium")
|
|
||||||
.resizable()
|
|
||||||
.aspectRatio(contentMode: .fill)
|
|
||||||
.frame(width: geometry.frame(in: .local).width, height: 80)
|
|
||||||
.clipped()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.frame(width: geometry.frame(in: .local).width, height: 80)
|
|
||||||
.overlay(alignment: .topLeading) {
|
|
||||||
if !item.num_name.isEmpty {
|
|
||||||
HStack(alignment: .center) {
|
|
||||||
Text(item.num_name)
|
|
||||||
.font(.system(size: 12))
|
|
||||||
.foregroundColor(.white)
|
|
||||||
.lineLimit(1)
|
|
||||||
}
|
|
||||||
.padding(3)
|
|
||||||
.background(
|
|
||||||
Color.black.opacity(0.6)
|
|
||||||
)
|
|
||||||
.cornerRadius(3)
|
|
||||||
.padding(3)
|
|
||||||
} else {
|
|
||||||
EmptyView()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Text(item.name)
|
|
||||||
.font(.system(size: 12))
|
|
||||||
.foregroundColor(Color(hex: "#333333"))
|
|
||||||
.lineLimit(1)
|
|
||||||
}
|
|
||||||
.frame(width: 120, height: 100)
|
|
||||||
.onTapGesture {
|
|
||||||
if let playUrl = URL(string: item.play) {
|
|
||||||
UIApplication.shared.open(playUrl)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#Preview {
|
|
||||||
FollowListView()
|
|
||||||
}
|
|
||||||
72
dimensionhub/Views/List/ListModel.swift
Normal file
72
dimensionhub/Views/List/ListModel.swift
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
//
|
||||||
|
// ListModel.swift
|
||||||
|
// dimensionhub
|
||||||
|
//
|
||||||
|
// Created by 安礼成 on 2025/4/8.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
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] = []
|
||||||
|
|
||||||
|
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):
|
||||||
|
await MainActor.run {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -5,77 +5,11 @@
|
|||||||
// Created by 安礼成 on 2025/2/21.
|
// Created by 安礼成 on 2025/2/21.
|
||||||
//
|
//
|
||||||
import SwiftUI
|
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] = []
|
|
||||||
|
|
||||||
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):
|
|
||||||
await MainActor.run {
|
|
||||||
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 {
|
struct ListView: View {
|
||||||
@Environment(\.presentationMode) var presentationMode
|
|
||||||
@AppStorage("userId") private var userId: String = Utils.defaultUserId()
|
@AppStorage("userId") private var userId: String = Utils.defaultUserId()
|
||||||
|
|
||||||
@State var detailModel = ListModel()
|
@State var detailModel = ListModel()
|
||||||
|
|
||||||
let id: Int
|
let id: Int
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
@ -86,7 +20,7 @@ struct ListView: View {
|
|||||||
.padding([.leading, .top, .bottom], 10)
|
.padding([.leading, .top, .bottom], 10)
|
||||||
.background(Color(hex: "#F2F2F2"), ignoresSafeAreaEdges: [.top])
|
.background(Color(hex: "#F2F2F2"), ignoresSafeAreaEdges: [.top])
|
||||||
|
|
||||||
VStack {
|
VStack(alignment: .center) {
|
||||||
// 渠道列表
|
// 渠道列表
|
||||||
HStack(alignment: .center, spacing: 15) {
|
HStack(alignment: .center, spacing: 15) {
|
||||||
ForEach(Array(detailModel.channels.enumerated()), id: \.offset) { idx, channel in
|
ForEach(Array(detailModel.channels.enumerated()), id: \.offset) { idx, channel in
|
||||||
@ -109,22 +43,6 @@ struct ListView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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()
|
Spacer()
|
||||||
}
|
}
|
||||||
.frame(width: 370, alignment: .center)
|
.frame(width: 370, alignment: .center)
|
||||||
Loading…
x
Reference in New Issue
Block a user