diff --git a/Reveil/DataModels/Presets/SecurityPresets.swift b/Reveil/DataModels/Presets/SecurityPresets.swift index 738d109..ed8ad62 100644 --- a/Reveil/DataModels/Presets/SecurityPresets.swift +++ b/Reveil/DataModels/Presets/SecurityPresets.swift @@ -88,6 +88,7 @@ struct SecurityPresets: Codable { "com.apple.security.network.client", "com.apple.private.security.container-required", "beta-reports-active", + "aps-environment", ] var secureMainBundleIdentifiers: Set = [ diff --git a/Reveil/Pages/DashboardView.swift b/Reveil/Pages/DashboardView.swift index e638841..d1d66a2 100644 --- a/Reveil/Pages/DashboardView.swift +++ b/Reveil/Pages/DashboardView.swift @@ -6,6 +6,9 @@ // import SwiftUI +#if canImport(UserNotifications) +import UserNotifications +#endif struct DashboardView: View, GlobalTimerObserver { let id = UUID() @@ -15,6 +18,28 @@ struct DashboardView: View, GlobalTimerObserver { @ObservedObject private var securityModel = Security.shared @State private var isNavigationLinkActive = false + private static var isUserNotificationAuthorizationRequested = false + private static var isUserNotificationAuthorizationRequestGranted = false + + @available(iOS 16.0, *) + private func updateBadgeCount() -> Void { + #if canImport(UserNotifications) + if !Self.isUserNotificationAuthorizationRequested { + UNUserNotificationCenter.current().requestAuthorization(options: [.badge]) { succeed, error in + if succeed { + let securityModelPresented: Bool = PinStorage.shared.isPinned(forKey: .Security) + UNUserNotificationCenter.current().setBadgeCount(securityModelPresented ? Security.shared.numberOfInsecureChecks : 0) + } + Self.isUserNotificationAuthorizationRequestGranted = succeed + Self.isUserNotificationAuthorizationRequested = true + } + } else if (Self.isUserNotificationAuthorizationRequestGranted) { + let securityModelPresented: Bool = PinStorage.shared.isPinned(forKey: .Security) + UNUserNotificationCenter.current().setBadgeCount(securityModelPresented ? Security.shared.numberOfInsecureChecks : 0) + } + #endif + } + var body: some View { ScrollView(.vertical) { VStack { @@ -44,11 +69,23 @@ struct DashboardView: View, GlobalTimerObserver { .padding() } .onAppear { + if #available(iOS 16.0, *) { + updateBadgeCount() + } GlobalTimer.shared.addObserver(self) } .onDisappear { GlobalTimer.shared.removeObserver(self) } + .onReceive(securityModel.$isLoading) { isLoading in + if #available(iOS 16.0, *) { + if !isLoading { + updateBadgeCount() + } + } else { + // Fallback on earlier versions + } + } } @ViewBuilder diff --git a/Reveil/Reveil.entitlements b/Reveil/Reveil.entitlements index ee95ab7..3e47d4d 100644 --- a/Reveil/Reveil.entitlements +++ b/Reveil/Reveil.entitlements @@ -2,6 +2,8 @@ + aps-environment + development com.apple.security.app-sandbox com.apple.security.network.client diff --git a/Reveil/ViewModels/Security.swift b/Reveil/ViewModels/Security.swift index 10b34b7..8e2ac2e 100644 --- a/Reveil/ViewModels/Security.swift +++ b/Reveil/ViewModels/Security.swift @@ -40,11 +40,13 @@ final class Security: ObservableObject, StaticEntryProvider, Explainable { @Published var isLoading: Bool @Published var isInsecure: Bool + @Published var numberOfInsecureChecks: Int private init() { basicEntries = [] isLoading = false isInsecure = false + numberOfInsecureChecks = 0 reloadData() } @@ -52,6 +54,10 @@ final class Security: ObservableObject, StaticEntryProvider, Explainable { checks.first { $0.isFailed } != nil } + private func countNumberOfInsecureChecks(_ checks: [SecurityCheck]) -> Int { + checks.filter { $0.isFailed }.count + } + func reloadData() { guard !isLoading else { return @@ -71,10 +77,11 @@ final class Security: ObservableObject, StaticEntryProvider, Explainable { let groupedEntries = Dictionary(grouping: performedEntries) { $0.children?.isEmpty ?? true } let allEntries = (groupedEntries[false] ?? []) + (groupedEntries[true] ?? []) - DispatchQueue.main.async { + DispatchQueue.main.async { [unowned self] in self.basicEntries.removeAll(keepingCapacity: true) self.basicEntries.append(contentsOf: allEntries) self.isInsecure = self.hasInsecureCheck(performedCases) + self.numberOfInsecureChecks = self.countNumberOfInsecureChecks(performedCases) self.isLoading = false } }