diff --git a/dimensionhub/Info.plist b/dimensionhub/Info.plist index fde08b1..6129aec 100644 --- a/dimensionhub/Info.plist +++ b/dimensionhub/Info.plist @@ -10,6 +10,11 @@ UIBackgroundModes remote-notification + fetch + BGTaskSchedulerPermittedIdentifiers + + com.jihe.dimensionhub.refresh + diff --git a/dimensionhub/Modifers/AutoDismissModifier.swift b/dimensionhub/Modifers/AutoDismissModifier.swift index 9b6259e..933f7c2 100644 --- a/dimensionhub/Modifers/AutoDismissModifier.swift +++ b/dimensionhub/Modifers/AutoDismissModifier.swift @@ -8,28 +8,31 @@ import SwiftUI // 自定义修饰符 extension View { - func autoDismiss(after seconds: Double) -> some View { - modifier(AutoDismissModifier(seconds: seconds)) + func autoDismiss(isHidden: Binding, after seconds: Double) -> some View { + modifier(AutoDismissModifier(isHidden: isHidden, seconds: seconds)) } } struct AutoDismissModifier: ViewModifier { + @Binding var isHidden: Bool let seconds: Double - @State private var isVisible = true - + func body(content: Content) -> some View { - if isVisible { - content - .onAppear { - Task { - try? await Task.sleep(for: .seconds(seconds)) - withAnimation(.easeOut) { - isVisible = false - } + content + .opacity(isHidden ? 0 : 1) + .frame(height: isHidden ? 0 : nil) + .onAppear { + Task { + print("call me task: \(isHidden)") + try? await Task.sleep(for: .seconds(seconds)) + withAnimation(.easeOut) { + isHidden = true } } - } else { - EmptyView() - } + } + .onChange(of: isHidden) { oldValue, newValue in + print("curernt value is: \(isHidden)") + } } + } diff --git a/dimensionhub/Views/Index/IndexMainView.swift b/dimensionhub/Views/Index/IndexMainView.swift index 91a1573..b124c7a 100644 --- a/dimensionhub/Views/Index/IndexMainView.swift +++ b/dimensionhub/Views/Index/IndexMainView.swift @@ -25,7 +25,7 @@ struct IndexMainView: View { @State private var showDateNavPopover: Bool = false // 前向刷新提示信息 - @State private var noMoreNewest: Bool = false + @State private var hasMoreNewest: Bool = true @State private var hasMoreOldest: Bool = false // 刷新逻辑 @@ -72,10 +72,15 @@ struct IndexMainView: View { ScrollView(.vertical, showsIndicators: false) { ScrollViewOffsetReader(offset: $scrollOffset) - if noMoreNewest { + if !hasMoreNewest { Text("没有了") .foregroundColor(.black) - .autoDismiss(after: 1.5) + .task { + try? await Task.sleep(for: .seconds(1.5)) + withAnimation(.easeOut) { + hasMoreNewest = true + } + } } MixGroupLabelView(fixedDramaGroup: indexModel.fixedDramaGroup) { @@ -125,15 +130,13 @@ struct IndexMainView: View { // 上拉刷新功能 self.headerRefreshing = true - self.noMoreNewest = false - Task { @MainActor in - await self.indexModel.loadPrevUpdateDramasTask(userId: self.userId) { hasData in + let loadNum = await self.indexModel.loadPrevUpdateDramasTask(userId: self.userId) { _ in DispatchQueue.main.async { self.headerRefreshing = false - self.noMoreNewest = !hasData } } + self.hasMoreNewest = loadNum > 3 } } .onChange(of: scrollID) { _, newValue in @@ -174,7 +177,7 @@ struct IndexMainView: View { return } - Task { @MainActor in + let task = Task { @MainActor in let num = await indexModel.loadMoreUpdateDramasTask(userId: self.userId) if num > 3 { self.hasMoreOldest = true diff --git a/dimensionhub/Views/Index/IndexModel.swift b/dimensionhub/Views/Index/IndexModel.swift index 29459be..2dc2084 100644 --- a/dimensionhub/Views/Index/IndexModel.swift +++ b/dimensionhub/Views/Index/IndexModel.swift @@ -262,13 +262,15 @@ final class IndexModel { return loadNum } - func loadPrevUpdateDramasTask(userId: String, callback: (Bool) -> Void) async { + func loadPrevUpdateDramasTask(userId: String, callback: (Bool) -> Void) async -> Int { guard !self.isMoreLoading else { - return + return 0 } // 按照id来判断不一定正确,需要借助其他值 let dramaIds = self.getDramaIds(self.updateDramaGroups) + + var loadNum: Int = 0 // 查找最小的id if let firstId = dramaIds.first { self.isMoreLoading = true @@ -283,6 +285,9 @@ final class IndexModel { self.dramaGroupElements = transformUpdateDramaGroups(groups: self.updateDramaGroups) displayDramaGroups(self.updateDramaGroups, label: "after") + + loadNum = groups.reduce(0, { acc, group in acc + group.items.count }) + // 处理回调 callback(true) } else { @@ -293,6 +298,8 @@ final class IndexModel { } self.isMoreLoading = false } + + return loadNum } // 转换成显示的元素信息 diff --git a/dimensionhub/dimensionhubApp.swift b/dimensionhub/dimensionhubApp.swift index 0c03712..6991fcc 100644 --- a/dimensionhub/dimensionhubApp.swift +++ b/dimensionhub/dimensionhubApp.swift @@ -8,6 +8,7 @@ import SwiftUI import SwiftData import Observation +import BackgroundTasks @main struct dimensionhubApp: App { @@ -97,7 +98,14 @@ struct dimensionhubApp: App { class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate { + let taskId = "com.jihe.dimensionhub.refresh" + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { + + BGTaskScheduler.shared.register(forTaskWithIdentifier: taskId, using: nil) { task in + self.handleAppRefresh(task: task as! BGAppRefreshTask) + } + Task.detached { await self.registerForPushNotifications() @@ -124,6 +132,42 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD return true } + private func handleAppRefresh(task: BGAppRefreshTask) { + self.scheduleAppRefresh() + + task.expirationHandler = { + // 清理未完成的操作 + task.setTaskCompleted(success: false) + } + + Task {@MainActor in + if let unreadNum = await self.fetchUserUnreadCount(), unreadNum > 0 { + do { + try await UNUserNotificationCenter.current().setBadgeCount(unreadNum) + task.setTaskCompleted(success: true) + NSLog("Refresh setBadgeCount num: \(unreadNum)") + } catch let err { + NSLog("Refresh setBadgeCount get error: \(err)") + task.setTaskCompleted(success: false) + } + } else { + task.setTaskCompleted(success: false) + } + } + } + + private func scheduleAppRefresh() { + let request = BGAppRefreshTaskRequest(identifier: taskId) + + // 设置下次执行时间(建议 1-4 小时) + request.earliestBeginDate = Date(timeIntervalSinceNow: 900) + do { + try BGTaskScheduler.shared.submit(request) + } catch { + NSLog("无法安排后台任务: \(error.localizedDescription)") + } + } + private func registerForPushNotifications() { // 请求通知权限 UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) {granted, error in