fix index view
This commit is contained in:
parent
cfe9dd5c2e
commit
f1790156f9
@ -28,9 +28,6 @@ struct IndexMainView: View {
|
|||||||
@State private var footerRefreshing: Bool = false
|
@State private var footerRefreshing: Bool = false
|
||||||
@State private var noMore: Bool = false
|
@State private var noMore: Bool = false
|
||||||
|
|
||||||
// 保存底部元素在global坐标系里面的minY值
|
|
||||||
@State private var footerOffset: Int = 0
|
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(alignment: .center) {
|
VStack(alignment: .center) {
|
||||||
|
|
||||||
@ -76,6 +73,7 @@ struct IndexMainView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ProgressView()
|
ProgressView()
|
||||||
|
.id(UUID())
|
||||||
.background(GeometryReader { geometry in
|
.background(GeometryReader { geometry in
|
||||||
let minY = geometry.frame(in: .global).minY
|
let minY = geometry.frame(in: .global).minY
|
||||||
Color.clear.preference(key: FooterOffsetPreferenceKey.self, value: Int(minY))
|
Color.clear.preference(key: FooterOffsetPreferenceKey.self, value: Int(minY))
|
||||||
@ -83,25 +81,12 @@ struct IndexMainView: View {
|
|||||||
}
|
}
|
||||||
.frame(width: 370)
|
.frame(width: 370)
|
||||||
.coordinateSpace(name: "indexScrollView")
|
.coordinateSpace(name: "indexScrollView")
|
||||||
.onScrollPhaseChange { oldPhase, newPhase in
|
|
||||||
guard !footerRefreshing && !showDateNavPopover else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
print("scroll old: \(oldPhase), new: \(newPhase), footer-offset: \(footerOffset)")
|
.onPreferenceChange(FooterOffsetPreferenceKey.self) { offset in
|
||||||
// 滑动停止的时候,检测是否到达了底部
|
// 延迟到当前帧结束更新state的值,避免导致循环更新的警告
|
||||||
let height = Int(UIScreen.main.bounds.height)
|
DispatchQueue.main.async {
|
||||||
let distance = height - footerOffset
|
indexModel.loadMorePublisher.send((userId, offset))
|
||||||
if newPhase == .idle && (distance >= 0 && distance < 50) {
|
|
||||||
self.footerRefreshing = true
|
|
||||||
Task {
|
|
||||||
await self.indexModel.loadMoreUpdateDramas(userId: self.userId, mode: .next)
|
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
|
|
||||||
self.footerRefreshing = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
.refreshable {
|
.refreshable {
|
||||||
guard !self.showDateNavPopover && !self.headerRefreshing else {
|
guard !self.showDateNavPopover && !self.headerRefreshing else {
|
||||||
@ -110,8 +95,12 @@ struct IndexMainView: View {
|
|||||||
|
|
||||||
// 上拉刷新功能
|
// 上拉刷新功能
|
||||||
self.headerRefreshing = true
|
self.headerRefreshing = true
|
||||||
await self.indexModel.loadMoreUpdateDramas(userId: self.userId, mode: .prev)
|
Task {
|
||||||
self.headerRefreshing = false
|
await self.indexModel.loadMoreUpdateDramasTask(userId: self.userId, mode: .prev)
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
self.headerRefreshing = false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.overlay(alignment: .topTrailing) {
|
.overlay(alignment: .topTrailing) {
|
||||||
HStack(alignment: .center) {
|
HStack(alignment: .center) {
|
||||||
@ -155,13 +144,9 @@ struct IndexMainView: View {
|
|||||||
.onPreferenceChange(DramaGroupElementPreferenceKey.self) { frames in
|
.onPreferenceChange(DramaGroupElementPreferenceKey.self) { frames in
|
||||||
let visibleFrames = frames.filter { $0.value >= 0}
|
let visibleFrames = frames.filter { $0.value >= 0}
|
||||||
if let minFrame = visibleFrames.min(by: { $0.value <= $1.value}) {
|
if let minFrame = visibleFrames.min(by: { $0.value <= $1.value}) {
|
||||||
indexModel.setFixedDrameGroup(groupId: minFrame.key)
|
DispatchQueue.main.async {
|
||||||
}
|
indexModel.setFixedDrameGroup(groupId: minFrame.key)
|
||||||
}
|
}
|
||||||
.onPreferenceChange(FooterOffsetPreferenceKey.self) { offset in
|
|
||||||
// 延迟到当前帧结束更新state的值,避免导致循环更新的警告
|
|
||||||
DispatchQueue.main.async {
|
|
||||||
self.footerOffset = offset
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,10 +253,7 @@ extension IndexMainView {
|
|||||||
static var defaultValue: Int = 0
|
static var defaultValue: Int = 0
|
||||||
|
|
||||||
static func reduce(value: inout Int, nextValue: () -> Int) {
|
static func reduce(value: inout Int, nextValue: () -> Int) {
|
||||||
let newValue = nextValue()
|
value += nextValue()
|
||||||
if newValue > 0 && abs(newValue - value) >= 50 {
|
|
||||||
value = newValue
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -7,6 +7,8 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
import Observation
|
import Observation
|
||||||
|
import Combine
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
@Observable
|
@Observable
|
||||||
final class IndexModel {
|
final class IndexModel {
|
||||||
@ -60,12 +62,45 @@ final class IndexModel {
|
|||||||
@ObservationIgnored
|
@ObservationIgnored
|
||||||
private var isLoaded = false
|
private var isLoaded = false
|
||||||
|
|
||||||
|
// 是否正在刷新
|
||||||
|
@ObservationIgnored
|
||||||
|
private var isMoreLoading = false
|
||||||
|
|
||||||
// 是否显示debug信息
|
// 是否显示debug信息
|
||||||
@ObservationIgnored
|
@ObservationIgnored
|
||||||
private var debug: Bool = false
|
private var debug: Bool = false
|
||||||
|
|
||||||
|
// 用来追踪最近的更新时间
|
||||||
|
@ObservationIgnored
|
||||||
|
private var updateInterval = Date()
|
||||||
|
|
||||||
|
// 用来记录追踪当前footer的offset的变化
|
||||||
|
@ObservationIgnored
|
||||||
|
var loadMorePublisher = PassthroughSubject<(String, Int), Never>()
|
||||||
|
|
||||||
|
@ObservationIgnored
|
||||||
|
private var bag = Set<AnyCancellable>()
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
self.selectedDate = ""
|
self.selectedDate = ""
|
||||||
|
|
||||||
|
self.loadMorePublisher
|
||||||
|
.debounce(for: 0.2, scheduler: RunLoop.main)
|
||||||
|
.dropFirst()
|
||||||
|
.sink { (userId, offset) in
|
||||||
|
// 判断更新周期
|
||||||
|
let timeDistance = self.updateInterval.distance(to: Date())
|
||||||
|
// 滑动停止的时候,检测是否到达了底部
|
||||||
|
let height = Int(UIScreen.main.bounds.height)
|
||||||
|
let distance = height - offset
|
||||||
|
if timeDistance > 1.0 && (distance >= 0 && distance < 50) {
|
||||||
|
Task {
|
||||||
|
await self.loadMoreUpdateDramasTask(userId: userId, mode: .next)
|
||||||
|
}
|
||||||
|
self.updateInterval = Date()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.store(in: &bag)
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadData(userId: String) async {
|
func loadData(userId: String) async {
|
||||||
@ -94,7 +129,11 @@ final class IndexModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadMoreUpdateDramas(userId: String, mode: API.LoadMode) async {
|
func loadMoreUpdateDramasTask(userId: String, mode: API.LoadMode) async {
|
||||||
|
guard !self.isMoreLoading else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// 按照id来判断不一定正确,需要借助其他值
|
// 按照id来判断不一定正确,需要借助其他值
|
||||||
let dramaIds = self.getDramaIds(self.updateDramaGroups)
|
let dramaIds = self.getDramaIds(self.updateDramaGroups)
|
||||||
print("current ids: \(dramaIds)")
|
print("current ids: \(dramaIds)")
|
||||||
@ -103,6 +142,7 @@ final class IndexModel {
|
|||||||
case .prev:
|
case .prev:
|
||||||
// 查找最小的id
|
// 查找最小的id
|
||||||
if let firstId = dramaIds.first {
|
if let firstId = dramaIds.first {
|
||||||
|
self.isMoreLoading = true
|
||||||
let response = await API.loadMoreUpdateDramas(userId: userId, mode: mode, id: firstId, as: [UpdateDramaGroup].self)
|
let response = await API.loadMoreUpdateDramas(userId: userId, mode: mode, id: firstId, as: [UpdateDramaGroup].self)
|
||||||
if case let .result(groups) = response {
|
if case let .result(groups) = response {
|
||||||
if groups.count > 0 {
|
if groups.count > 0 {
|
||||||
@ -114,9 +154,11 @@ final class IndexModel {
|
|||||||
displayDramaGroups(self.updateDramaGroups, label: "after")
|
displayDramaGroups(self.updateDramaGroups, label: "after")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
self.isMoreLoading = false
|
||||||
}
|
}
|
||||||
case .next:
|
case .next:
|
||||||
if let lastId = dramaIds.last {
|
if let lastId = dramaIds.last {
|
||||||
|
self.isMoreLoading = true
|
||||||
let response = await API.loadMoreUpdateDramas(userId: userId, mode: mode, id: lastId, as: [UpdateDramaGroup].self)
|
let response = await API.loadMoreUpdateDramas(userId: userId, mode: mode, id: lastId, as: [UpdateDramaGroup].self)
|
||||||
if case let .result(groups) = response {
|
if case let .result(groups) = response {
|
||||||
if groups.count > 0 {
|
if groups.count > 0 {
|
||||||
@ -128,6 +170,8 @@ final class IndexModel {
|
|||||||
displayDramaGroups(self.updateDramaGroups, label: "after")
|
displayDramaGroups(self.updateDramaGroups, label: "after")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.isMoreLoading = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user