添加未读消息的后台更新逻辑

This commit is contained in:
anlicheng 2025-07-29 18:10:06 +08:00
parent ea022e56d3
commit b0c89d9998
5 changed files with 87 additions and 25 deletions

View File

@ -10,6 +10,11 @@
<key>UIBackgroundModes</key> <key>UIBackgroundModes</key>
<array> <array>
<string>remote-notification</string> <string>remote-notification</string>
<string>fetch</string>
</array> </array>
<key>BGTaskSchedulerPermittedIdentifiers</key>
<array>
<string>com.jihe.dimensionhub.refresh</string>
</array>
</dict> </dict>
</plist> </plist>

View File

@ -8,28 +8,31 @@ import SwiftUI
// //
extension View { extension View {
func autoDismiss(after seconds: Double) -> some View { func autoDismiss(isHidden: Binding<Bool>, after seconds: Double) -> some View {
modifier(AutoDismissModifier(seconds: seconds)) modifier(AutoDismissModifier(isHidden: isHidden, seconds: seconds))
} }
} }
struct AutoDismissModifier: ViewModifier { struct AutoDismissModifier: ViewModifier {
@Binding var isHidden: Bool
let seconds: Double let seconds: Double
@State private var isVisible = true
func body(content: Content) -> some View { func body(content: Content) -> some View {
if isVisible { content
content .opacity(isHidden ? 0 : 1)
.onAppear { .frame(height: isHidden ? 0 : nil)
Task { .onAppear {
try? await Task.sleep(for: .seconds(seconds)) Task {
withAnimation(.easeOut) { print("call me task: \(isHidden)")
isVisible = false try? await Task.sleep(for: .seconds(seconds))
} withAnimation(.easeOut) {
isHidden = true
} }
} }
} else { }
EmptyView() .onChange(of: isHidden) { oldValue, newValue in
} print("curernt value is: \(isHidden)")
}
} }
} }

View File

@ -25,7 +25,7 @@ struct IndexMainView: View {
@State private var showDateNavPopover: Bool = false @State private var showDateNavPopover: Bool = false
// //
@State private var noMoreNewest: Bool = false @State private var hasMoreNewest: Bool = true
@State private var hasMoreOldest: Bool = false @State private var hasMoreOldest: Bool = false
// //
@ -72,10 +72,15 @@ struct IndexMainView: View {
ScrollView(.vertical, showsIndicators: false) { ScrollView(.vertical, showsIndicators: false) {
ScrollViewOffsetReader(offset: $scrollOffset) ScrollViewOffsetReader(offset: $scrollOffset)
if noMoreNewest { if !hasMoreNewest {
Text("没有了") Text("没有了")
.foregroundColor(.black) .foregroundColor(.black)
.autoDismiss(after: 1.5) .task {
try? await Task.sleep(for: .seconds(1.5))
withAnimation(.easeOut) {
hasMoreNewest = true
}
}
} }
MixGroupLabelView(fixedDramaGroup: indexModel.fixedDramaGroup) { MixGroupLabelView(fixedDramaGroup: indexModel.fixedDramaGroup) {
@ -125,15 +130,13 @@ struct IndexMainView: View {
// //
self.headerRefreshing = true self.headerRefreshing = true
self.noMoreNewest = false
Task { @MainActor in 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 { DispatchQueue.main.async {
self.headerRefreshing = false self.headerRefreshing = false
self.noMoreNewest = !hasData
} }
} }
self.hasMoreNewest = loadNum > 3
} }
} }
.onChange(of: scrollID) { _, newValue in .onChange(of: scrollID) { _, newValue in
@ -174,7 +177,7 @@ struct IndexMainView: View {
return return
} }
Task { @MainActor in let task = Task { @MainActor in
let num = await indexModel.loadMoreUpdateDramasTask(userId: self.userId) let num = await indexModel.loadMoreUpdateDramasTask(userId: self.userId)
if num > 3 { if num > 3 {
self.hasMoreOldest = true self.hasMoreOldest = true

View File

@ -262,13 +262,15 @@ final class IndexModel {
return loadNum return loadNum
} }
func loadPrevUpdateDramasTask(userId: String, callback: (Bool) -> Void) async { func loadPrevUpdateDramasTask(userId: String, callback: (Bool) -> Void) async -> Int {
guard !self.isMoreLoading else { guard !self.isMoreLoading else {
return return 0
} }
// id // id
let dramaIds = self.getDramaIds(self.updateDramaGroups) let dramaIds = self.getDramaIds(self.updateDramaGroups)
var loadNum: Int = 0
// id // id
if let firstId = dramaIds.first { if let firstId = dramaIds.first {
self.isMoreLoading = true self.isMoreLoading = true
@ -283,6 +285,9 @@ final class IndexModel {
self.dramaGroupElements = transformUpdateDramaGroups(groups: self.updateDramaGroups) self.dramaGroupElements = transformUpdateDramaGroups(groups: self.updateDramaGroups)
displayDramaGroups(self.updateDramaGroups, label: "after") displayDramaGroups(self.updateDramaGroups, label: "after")
loadNum = groups.reduce(0, { acc, group in acc + group.items.count })
// //
callback(true) callback(true)
} else { } else {
@ -293,6 +298,8 @@ final class IndexModel {
} }
self.isMoreLoading = false self.isMoreLoading = false
} }
return loadNum
} }
// //

View File

@ -8,6 +8,7 @@
import SwiftUI import SwiftUI
import SwiftData import SwiftData
import Observation import Observation
import BackgroundTasks
@main @main
struct dimensionhubApp: App { struct dimensionhubApp: App {
@ -97,7 +98,14 @@ struct dimensionhubApp: App {
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate { class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {
let taskId = "com.jihe.dimensionhub.refresh"
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { 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 { Task.detached {
await self.registerForPushNotifications() await self.registerForPushNotifications()
@ -124,6 +132,42 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
return true 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() { private func registerForPushNotifications() {
// //
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) {granted, error in UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) {granted, error in