diff --git a/apps/ios/Shared/AppDelegate.swift b/apps/ios/Shared/AppDelegate.swift index 48fe8ee37..236784a39 100644 --- a/apps/ios/Shared/AppDelegate.swift +++ b/apps/ios/Shared/AppDelegate.swift @@ -61,7 +61,7 @@ class AppDelegate: NSObject, UIApplicationDelegate { m.notificationMode != .off { if let verification = ntfData["verification"] as? String, let nonce = ntfData["nonce"] as? String { - if let token = ChatModel.shared.deviceToken { + if let token = m.deviceToken { logger.debug("AppDelegate: didReceiveRemoteNotification: verification, confirming \(verification)") Task { do { @@ -81,7 +81,7 @@ class AppDelegate: NSObject, UIApplicationDelegate { } } else if let checkMessages = ntfData["checkMessages"] as? Bool, checkMessages { logger.debug("AppDelegate: didReceiveRemoteNotification: checkMessages") - if appStateGroupDefault.get().inactive { + if appStateGroupDefault.get().inactive && m.ntfEnablePeriodic { receiveMessages(completionHandler) } else { completionHandler(.noData) diff --git a/apps/ios/Shared/Model/BGManager.swift b/apps/ios/Shared/Model/BGManager.swift index e10012c11..5ee52407b 100644 --- a/apps/ios/Shared/Model/BGManager.swift +++ b/apps/ios/Shared/Model/BGManager.swift @@ -34,6 +34,10 @@ class BGManager { } func schedule() { + if !ChatModel.shared.ntfEnableLocal { + logger.debug("BGManager.schedule: disabled") + return + } logger.debug("BGManager.schedule") let request = BGAppRefreshTaskRequest(identifier: receiveTaskId) request.earliestBeginDate = Date(timeIntervalSinceNow: bgRefreshInterval) @@ -45,6 +49,10 @@ class BGManager { } private func handleRefresh(_ task: BGAppRefreshTask) { + if !ChatModel.shared.ntfEnableLocal { + logger.debug("BGManager.handleRefresh: disabled") + return + } logger.debug("BGManager.handleRefresh") schedule() if appStateGroupDefault.get().inactive { diff --git a/apps/ios/Shared/Model/ChatModel.swift b/apps/ios/Shared/Model/ChatModel.swift index 62f14c792..3179b4f86 100644 --- a/apps/ios/Shared/Model/ChatModel.swift +++ b/apps/ios/Shared/Model/ChatModel.swift @@ -42,7 +42,7 @@ final class ChatModel: ObservableObject { @Published var tokenRegistered = false @Published var tokenStatus: NtfTknStatus? @Published var notificationMode = NotificationsMode.off - @Published var notificationPreview: NotificationPreviewMode? = ntfPreviewModeGroupDefault.get() + @Published var notificationPreview: NotificationPreviewMode = ntfPreviewModeGroupDefault.get() @Published var incognito: Bool = incognitoGroupDefault.get() // pending notification actions @Published var ntfContactRequest: ChatId? @@ -69,6 +69,14 @@ final class ChatModel: ObservableObject { static var ok: Bool { ChatModel.shared.chatDbStatus == .ok } + var ntfEnableLocal: Bool { + notificationMode == .off || ntfEnableLocalGroupDefault.get() + } + + var ntfEnablePeriodic: Bool { + notificationMode == .periodic || ntfEnablePeriodicGroupDefault.get() + } + func getUser(_ userId: Int64) -> User? { currentUser?.userId == userId ? currentUser diff --git a/apps/ios/Shared/Views/UserSettings/NotificationsView.swift b/apps/ios/Shared/Views/UserSettings/NotificationsView.swift index 4e4001b24..1f8abc561 100644 --- a/apps/ios/Shared/Views/UserSettings/NotificationsView.swift +++ b/apps/ios/Shared/Views/UserSettings/NotificationsView.swift @@ -11,9 +11,12 @@ import SimpleXChat struct NotificationsView: View { @EnvironmentObject var m: ChatModel - @State private var notificationMode: NotificationsMode? + @State private var notificationMode: NotificationsMode = ChatModel.shared.notificationMode @State private var showAlert: NotificationAlert? @State private var legacyDatabase = dbContainerGroupDefault.get() == .documents + @AppStorage(DEFAULT_DEVELOPER_TOOLS) private var developerTools = false + @AppStorage(GROUP_DEFAULT_NTF_ENABLE_LOCAL, store: groupDefaults) private var ntfEnableLocal = false + @AppStorage(GROUP_DEFAULT_NTF_ENABLE_PERIODIC, store: groupDefaults) private var ntfEnablePeriodic = false var body: some View { List { @@ -26,9 +29,7 @@ struct NotificationsView: View { } } footer: { VStack(alignment: .leading) { - if let mode = notificationMode { - Text(ntfModeDescription(mode)) - } + Text(ntfModeDescription(notificationMode)) } .font(.callout) .padding(.top, 1) @@ -43,7 +44,6 @@ struct NotificationsView: View { return Alert(title: Text("No device token!")) } } - .onAppear { notificationMode = m.notificationMode } } label: { HStack { Text("Send notifications") @@ -76,7 +76,7 @@ struct NotificationsView: View { HStack { Text("Show preview") Spacer() - Text(m.notificationPreview?.label ?? "") + Text(m.notificationPreview.label) } } } header: { @@ -88,8 +88,15 @@ struct NotificationsView: View { .padding(.top, 1) } } - .disabled(legacyDatabase) + + if developerTools { + Section(String("Experimental")) { + Toggle(String("Always enable local"), isOn: $ntfEnableLocal) + Toggle(String("Always enable periodic"), isOn: $ntfEnablePeriodic) + } + } } + .disabled(legacyDatabase) } private func notificationAlert(_ alert: NotificationAlert, _ token: DeviceToken) -> Alert { @@ -166,7 +173,7 @@ func ntfModeDescription(_ mode: NotificationsMode) -> LocalizedStringKey { struct SelectionListView: View { var list: [Item] - @Binding var selection: Item? + @Binding var selection: Item var onSelection: ((Item) -> Void)? @State private var tapped: Item? = nil diff --git a/apps/ios/SimpleXChat/AppGroup.swift b/apps/ios/SimpleXChat/AppGroup.swift index a9de1da15..65907d89f 100644 --- a/apps/ios/SimpleXChat/AppGroup.swift +++ b/apps/ios/SimpleXChat/AppGroup.swift @@ -13,6 +13,8 @@ let GROUP_DEFAULT_APP_STATE = "appState" let GROUP_DEFAULT_DB_CONTAINER = "dbContainer" public let GROUP_DEFAULT_CHAT_LAST_START = "chatLastStart" let GROUP_DEFAULT_NTF_PREVIEW_MODE = "ntfPreviewMode" +public let GROUP_DEFAULT_NTF_ENABLE_LOCAL = "ntfEnableLocal" +public let GROUP_DEFAULT_NTF_ENABLE_PERIODIC = "ntfEnablePeriodic" let GROUP_DEFAULT_PRIVACY_ACCEPT_IMAGES = "privacyAcceptImages" public let GROUP_DEFAULT_PRIVACY_TRANSFER_IMAGES_INLINE = "privacyTransferImagesInline" // no longer used let GROUP_DEFAULT_NTF_BADGE_COUNT = "ntgBadgeCount" @@ -39,6 +41,8 @@ public let groupDefaults = UserDefaults(suiteName: APP_GROUP_NAME)! public func registerGroupDefaults() { groupDefaults.register(defaults: [ + GROUP_DEFAULT_NTF_ENABLE_LOCAL: false, + GROUP_DEFAULT_NTF_ENABLE_PERIODIC: false, GROUP_DEFAULT_NETWORK_USE_ONION_HOSTS: OnionHosts.no.rawValue, GROUP_DEFAULT_NETWORK_SESSION_MODE: TransportSessionMode.user.rawValue, GROUP_DEFAULT_NETWORK_TCP_CONNECT_TIMEOUT: NetCfg.defaults.tcpConnectTimeout, @@ -103,6 +107,10 @@ public let ntfPreviewModeGroupDefault = EnumDefault( public let incognitoGroupDefault = BoolDefault(defaults: groupDefaults, forKey: GROUP_DEFAULT_INCOGNITO) +public let ntfEnableLocalGroupDefault = BoolDefault(defaults: groupDefaults, forKey: GROUP_DEFAULT_NTF_ENABLE_LOCAL) + +public let ntfEnablePeriodicGroupDefault = BoolDefault(defaults: groupDefaults, forKey: GROUP_DEFAULT_NTF_ENABLE_PERIODIC) + public let privacyAcceptImagesGroupDefault = BoolDefault(defaults: groupDefaults, forKey: GROUP_DEFAULT_PRIVACY_ACCEPT_IMAGES) public let privacyTransferImagesInlineGroupDefault = BoolDefault(defaults: groupDefaults, forKey: GROUP_DEFAULT_PRIVACY_TRANSFER_IMAGES_INLINE)