From 2175a8c74edb7a08ec5c62ead8419312dd291a01 Mon Sep 17 00:00:00 2001 From: anlicheng <244108715@qq.com> Date: Tue, 25 Feb 2025 23:28:01 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=BF=87=E6=B8=A1=E9=A1=B5?= =?UTF-8?q?=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lost_network.imageset/Contents.json | 21 ++ .../lost_network.imageset/lost.jpg | Bin 0 -> 6369 bytes dimensionhub/Views/DateNavView.swift | 2 +- dimensionhub/Views/IndexView.swift | 312 +++++++++++------- 4 files changed, 218 insertions(+), 117 deletions(-) create mode 100644 dimensionhub/Assets.xcassets/lost_network.imageset/Contents.json create mode 100644 dimensionhub/Assets.xcassets/lost_network.imageset/lost.jpg diff --git a/dimensionhub/Assets.xcassets/lost_network.imageset/Contents.json b/dimensionhub/Assets.xcassets/lost_network.imageset/Contents.json new file mode 100644 index 0000000..f6cb6e4 --- /dev/null +++ b/dimensionhub/Assets.xcassets/lost_network.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "lost.jpg", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/dimensionhub/Assets.xcassets/lost_network.imageset/lost.jpg b/dimensionhub/Assets.xcassets/lost_network.imageset/lost.jpg new file mode 100644 index 0000000000000000000000000000000000000000..498911289dc0007d6640ebf926b66c782600cb1a GIT binary patch literal 6369 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 50 && contextFrame.minY > 0 && !isMoreLoading { - Task { - self.isMoreLoading = true - let result = await self.indexModel.loadMoreUpdateDramas(userId: self.userId, mode: .next) - switch result { - case .success: - () - case .error(let message): - DispatchQueue.main.async { - self.showPrompt = true - self.promptMessage = message - } - } - self.isMoreLoading = false - } - } - } - }) - - if self.isMoreLoading { - ProgressView() + ZStack { + switch self.networkStatus { + case .unsatisfied: + IndexExceptionView { + self.checkNetworkStatus() } + case .satisfied: + IndexMainView() } - .coordinateSpace(name: "scrollView") - .popover(isPresented: $showDateNavPopover) { - DateNavView(selectGroupId: self.$selectGroupId, showDateNavPopover: $showDateNavPopover) { selectedDate in - Task { - await indexModel.loadDateUpdateDramas(userId: self.userId, date: selectedDate) - } - } - } - .refreshable { - guard !self.isPrevLoading else { - return - } - - // 上拉刷新功能 - self.isPrevLoading = true - let result = await self.indexModel.loadMoreUpdateDramas(userId: self.userId, mode: .prev) - switch result { - case .success: - () - case .error(let message): - DispatchQueue.main.asyncAfter(deadline: .now() + 1) { - self.showPrompt = true - self.promptMessage = message - } - } - self.isPrevLoading = false - } - } - .frame(width: 370) - .ignoresSafeArea(edges: .bottom) - .alert(isPresented: $showPrompt) { - Alert(title: Text("提示"), message: Text(self.promptMessage), dismissButton: .default(Text("OK"))) - } - .task { - await self.indexModel.loadData(userId: self.userId) + .onAppear { + self.checkNetworkStatus() } } + + private func checkNetworkStatus() { + let monitor = NWPathMonitor() + monitor.pathUpdateHandler = { path in + DispatchQueue.main.async { + switch path.status { + case .satisfied: + self.networkStatus = .satisfied + default: + self.networkStatus = .unsatisfied + } + } + } + monitor.start(queue: Self.queue) + } + } extension IndexView { + struct IndexExceptionView: View { + let onRetry: () -> Void + + var body: some View { + HStack { + Spacer() + VStack(alignment: .center, spacing: 20) { + Spacer() + Image("lost_network") + + Text("网络状态待提升,点击重试") + .font(.system(size: 13)) + .foregroundColor(Color(hex: "#333333")) + + Rectangle() + .frame(width: 100, height: 25) + .foregroundColor(Color(hex: "#F2F2F2")) + .overlay { + Text("重新加载") + .font(.system(size: 13)) + .foregroundColor(Color(hex: "#999999")) + .fontWeight(.regular) + } + .onTapGesture { + onRetry() + } + Spacer() + } + Spacer() + } + .background(Color(hex: "#F6F6F6"), ignoresSafeAreaEdges: .all) + } + } + + + // 首页的主要窗口 + struct IndexMainView: View { + @Environment(\.modelContext) private var modelContext + @AppStorage("userId") private var userId: String = Utils.defaultUserId() + + @State var indexModel = IndexModel() + @State var isMoreLoading: Bool = false + // 前向刷新 + @State var isPrevLoading: Bool = false + + // 提示信息 + @State var showPrompt: Bool = false + @State var promptMessage: String = "" + + // 是否显示日期弹出层 + @State private var selectGroupId: String = "" + @State private var showDateNavPopover: Bool = false + + var body: some View { + VStack(alignment: .center) { + + HStack(alignment: .center) { + Color.clear + .overlay { + Text("亚次元") + .font(.system(size: 16)) + .padding([.top, .bottom], 5) + } + } + .frame(height: 50) + .background(Color(hex: "#F2F2F2"), ignoresSafeAreaEdges: .bottom) + + HStack(alignment: .center) { + Spacer() + Text("番剧补完计划") + .font(.system(size: 24)) + .foregroundColor(Color(hex: "#999999")) + } + + ForEach(indexModel.dramas, id: \.id) { drama in + DramaCellView(dramaItem: drama) + } + + // 基于日期的更新列表 + ScrollView(.vertical, showsIndicators: false) { + VStack(alignment: .center, spacing: 10) { + ForEach(indexModel.updateDramaGroups, id: \.group_id) { group in + DramaGroupView(group: group) { + selectGroupId = group.group_id + indexModel.selectedDate = group.group_id + showDateNavPopover = true + } + } + } + + Rectangle() + .frame(height: 0) + .background(GeometryReader { + geometry in + Color.clear.onChange(of: geometry.frame(in: .global).minY) {_, offset in + + let frame = geometry.frame(in: .global) + let screenBounds = UIScreen.main.bounds + let contextFrame = geometry.frame(in: .named("scrollView")) + + if screenBounds.height - frame.minY > 50 && contextFrame.minY > 0 && !isMoreLoading { + Task { + self.isMoreLoading = true + let result = await self.indexModel.loadMoreUpdateDramas(userId: self.userId, mode: .next) + switch result { + case .success: + () + case .error(let message): + DispatchQueue.main.async { + self.showPrompt = true + self.promptMessage = message + } + } + self.isMoreLoading = false + } + } + } + }) + + if self.isMoreLoading { + ProgressView() + } + } + .coordinateSpace(name: "scrollView") + .popover(isPresented: $showDateNavPopover) { + DateNavView(selectGroupId: self.$selectGroupId, showDateNavPopover: $showDateNavPopover) { selectedDate in + Task { + await indexModel.loadDateUpdateDramas(userId: self.userId, date: selectedDate) + } + } + } + .refreshable { + guard !self.isPrevLoading else { + return + } + + // 上拉刷新功能 + self.isPrevLoading = true + let result = await self.indexModel.loadMoreUpdateDramas(userId: self.userId, mode: .prev) + switch result { + case .success: + () + case .error(let message): + DispatchQueue.main.asyncAfter(deadline: .now() + 1) { + self.showPrompt = true + self.promptMessage = message + } + } + self.isPrevLoading = false + } + + } + .frame(width: 370) + .ignoresSafeArea(edges: .bottom) + .alert(isPresented: $showPrompt) { + Alert(title: Text("提示"), message: Text(self.promptMessage), dismissButton: .default(Text("OK"))) + } + .task { + await self.indexModel.loadData(userId: self.userId) + } + } + } + // 显示剧集的列表信息 struct DramaCellView: View { let dramaItem: IndexModel.DramaItem @@ -379,7 +460,6 @@ extension IndexView { } } - // 显示分组信息 struct DramaGroupView: View { let group: IndexModel.UpdateDramaGroup