mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-24 07:05:35 +00:00
Calculate local unread count before applying notification
This commit is contained in:
@@ -1,13 +1,6 @@
|
||||
#ifndef NotificationService_BridgingHeader_h
|
||||
#define NotificationService_BridgingHeader_h
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <BuildConfig/BuildConfig.h>
|
||||
|
||||
@protocol SyncProvider <NSObject>
|
||||
|
||||
- (void)addIncomingMessageWithRootPath:(NSString * _Nonnull)rootPath accountId:(int64_t)accountId encryptionParameters:(DeviceSpecificEncryptionParameters * _Nonnull)encryptionParameters peerId:(int64_t)peerId messageId:(int32_t)messageId completion:(void (^)(int32_t))completion;
|
||||
|
||||
@end
|
||||
#import "NotificationService.h"
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,9 +1,16 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UserNotifications/UserNotifications.h>
|
||||
#import <BuildConfig/BuildConfig.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface NotificationService : UNNotificationServiceExtension
|
||||
@interface NotificationServiceImpl : NSObject
|
||||
|
||||
- (instancetype)initWithCountIncomingMessage:(void (^)(NSString *, int64_t, DeviceSpecificEncryptionParameters *, int64_t, int32_t))countIncomingMessage;
|
||||
|
||||
- (void)updateUnreadCount:(int32_t)unreadCount;
|
||||
- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler;
|
||||
- (void)serviceExtensionTimeWillExpire;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#import "NotificationService.h"
|
||||
|
||||
#import <mach/mach.h>
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <BuildConfig/BuildConfig.h>
|
||||
|
||||
@@ -34,47 +36,43 @@ static int64_t makePeerId(int32_t namespace, int32_t value) {
|
||||
return (((int64_t)(namespace)) << 32) | ((int64_t)((uint64_t)((uint32_t)value)));
|
||||
}
|
||||
|
||||
@interface ParsedNotificationMessage : NSObject
|
||||
|
||||
@property (nonatomic, readonly) int64_t accountId;
|
||||
@property (nonatomic, readonly) int64_t peerId;
|
||||
@property (nonatomic, readonly) int32_t messageId;
|
||||
|
||||
@end
|
||||
|
||||
@implementation ParsedNotificationMessage
|
||||
|
||||
- (instancetype)initWithAccountId:(int64_t)accountId peerId:(int64_t)peerId messageId:(int64_t)messageId {
|
||||
self = [super init];
|
||||
if (self != nil) {
|
||||
_accountId = accountId;
|
||||
_peerId = peerId;
|
||||
_messageId = messageId;
|
||||
static void reportMemory() {
|
||||
struct task_basic_info info;
|
||||
mach_msg_type_number_t size = TASK_BASIC_INFO_COUNT;
|
||||
kern_return_t kerr = task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&info, &size);
|
||||
if (kerr == KERN_SUCCESS) {
|
||||
NSLog(@"Memory in use (in bytes): %lu", info.resident_size);
|
||||
NSLog(@"Memory in use (in MiB): %f", ((CGFloat)info.resident_size / 1048576));
|
||||
} else {
|
||||
NSLog(@"Error with task_info(): %s", mach_error_string(kerr));
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface NotificationService () {
|
||||
@interface NotificationServiceImpl () {
|
||||
void (^_countIncomingMessage)(NSString *, int64_t, DeviceSpecificEncryptionParameters *, int64_t, int32_t);
|
||||
|
||||
NSString * _Nullable _rootPath;
|
||||
DeviceSpecificEncryptionParameters * _Nullable _deviceSpecificEncryptionParameters;
|
||||
NSString * _Nullable _baseAppBundleId;
|
||||
void (^_contentHandler)(UNNotificationContent *);
|
||||
UNMutableNotificationContent * _Nullable _bestAttemptContent;
|
||||
void (^_cancelFetch)(void);
|
||||
|
||||
ParsedNotificationMessage * _Nullable _parsedMessage;
|
||||
NSNumber * _Nullable _updatedUnreadCount;
|
||||
bool _contentReady;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation NotificationService
|
||||
@implementation NotificationServiceImpl
|
||||
|
||||
- (instancetype)init {
|
||||
- (instancetype)initWithCountIncomingMessage:(void (^)(NSString *, int64_t, DeviceSpecificEncryptionParameters *, int64_t, int32_t))countIncomingMessage {
|
||||
self = [super init];
|
||||
if (self != nil) {
|
||||
reportMemory();
|
||||
|
||||
_countIncomingMessage = [countIncomingMessage copy];
|
||||
|
||||
NSString *appBundleIdentifier = [NSBundle mainBundle].bundleIdentifier;
|
||||
NSRange lastDotRange = [appBundleIdentifier rangeOfString:@"." options:NSBackwardsSearch];
|
||||
if (lastDotRange.location != NSNotFound) {
|
||||
@@ -85,6 +83,9 @@ static int64_t makePeerId(int32_t namespace, int32_t value) {
|
||||
if (appGroupUrl != nil) {
|
||||
NSString *rootPath = [[appGroupUrl path] stringByAppendingPathComponent:@"telegram-data"];
|
||||
_rootPath = rootPath;
|
||||
if (rootPath != nil) {
|
||||
_deviceSpecificEncryptionParameters = [BuildConfig deviceSpecificEncryptionParameters:rootPath baseAppBundleId:_baseAppBundleId];
|
||||
}
|
||||
} else {
|
||||
NSAssert(false, @"appGroupUrl == nil");
|
||||
}
|
||||
@@ -97,6 +98,7 @@ static int64_t makePeerId(int32_t namespace, int32_t value) {
|
||||
|
||||
- (void)completeWithBestAttemptContent {
|
||||
_contentReady = true;
|
||||
//_updatedUnreadCount = @(-1);
|
||||
if (_contentReady && _updatedUnreadCount) {
|
||||
[self _internalComplete];
|
||||
}
|
||||
@@ -110,6 +112,8 @@ static int64_t makePeerId(int32_t namespace, int32_t value) {
|
||||
}
|
||||
|
||||
- (void)_internalComplete {
|
||||
reportMemory();
|
||||
|
||||
#ifdef __IPHONE_13_0
|
||||
if (_baseAppBundleId != nil) {
|
||||
BGAppRefreshTaskRequest *request = [[BGAppRefreshTaskRequest alloc] initWithIdentifier:[_baseAppBundleId stringByAppendingString:@".refresh"]];
|
||||
@@ -193,16 +197,9 @@ static int64_t makePeerId(int32_t namespace, int32_t value) {
|
||||
peerId = makePeerId(PeerNamespaceCloudChannel, [channelIdString intValue]);
|
||||
}
|
||||
|
||||
_parsedMessage = [[ParsedNotificationMessage alloc] initWithAccountId:account.accountId peerId:peerId messageId:messageId];
|
||||
|
||||
__weak NotificationService *weakSelf = self;
|
||||
[self addUnreadMessage:_rootPath accountId:account.accountId encryptionParameters:nil peerId:peerId messageId:messageId completion:^(int32_t badge) {
|
||||
__strong NotificationService *strongSelf = weakSelf;
|
||||
if (strongSelf == nil) {
|
||||
return;
|
||||
}
|
||||
[strongSelf updateUnreadCount:badge];
|
||||
}];
|
||||
if (_countIncomingMessage && _deviceSpecificEncryptionParameters) {
|
||||
_countIncomingMessage(_rootPath, account.accountId, _deviceSpecificEncryptionParameters, peerId, messageId);
|
||||
}
|
||||
|
||||
NSString *silentString = decryptedPayload[@"silent"];
|
||||
if ([silentString isKindOfClass:[NSString class]]) {
|
||||
@@ -375,10 +372,10 @@ static int64_t makePeerId(int32_t namespace, int32_t value) {
|
||||
} else {
|
||||
BuildConfig *buildConfig = [[BuildConfig alloc] initWithBaseAppBundleId:_baseAppBundleId];
|
||||
|
||||
__weak NotificationService *weakSelf = self;
|
||||
__weak typeof(self) weakSelf = self;
|
||||
_cancelFetch = fetchImage(buildConfig, accountInfos.proxy, account, inputFileLocation, fileDatacenterId, ^(NSData * _Nullable data) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
__strong NotificationService *strongSelf = weakSelf;
|
||||
__strong typeof(weakSelf) strongSelf = weakSelf;
|
||||
if (strongSelf == nil) {
|
||||
return;
|
||||
}
|
||||
@@ -431,11 +428,4 @@ static int64_t makePeerId(int32_t namespace, int32_t value) {
|
||||
}
|
||||
}
|
||||
|
||||
- (void)addUnreadMessage:(NSString * _Nonnull)rootPath accountId:(int64_t)accountId encryptionParameters:(DeviceSpecificEncryptionParameters * _Nonnull)encryptionParameters peerId:(int64_t)peerId messageId:(int32_t)messageId completion:(void (^)(int32_t))completion {
|
||||
|
||||
if (completion) {
|
||||
completion(-1);
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
31
NotificationService/NotificationService.swift
Normal file
31
NotificationService/NotificationService.swift
Normal file
@@ -0,0 +1,31 @@
|
||||
import Foundation
|
||||
import UserNotifications
|
||||
|
||||
@available(iOSApplicationExtension 10.0, *)
|
||||
@objc(NotificationService)
|
||||
final class NotificationService: UNNotificationServiceExtension {
|
||||
private let impl: NotificationServiceImpl
|
||||
|
||||
override init() {
|
||||
var completion: ((Int32) -> Void)?
|
||||
self.impl = NotificationServiceImpl(countIncomingMessage: { rootPath, accountId, encryptionParameters, peerId, messageId in
|
||||
SyncProviderImpl().addIncomingMessage(withRootPath: rootPath, accountId: accountId, encryptionParameters: encryptionParameters, peerId: peerId, messageId: messageId, completion: { count in
|
||||
completion?(count)
|
||||
})
|
||||
})
|
||||
|
||||
super.init()
|
||||
|
||||
completion = { [weak self] count in
|
||||
self?.impl.updateUnreadCount(count)
|
||||
}
|
||||
}
|
||||
|
||||
override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
|
||||
self.impl.didReceive(request, withContentHandler: contentHandler)
|
||||
}
|
||||
|
||||
override func serviceExtensionTimeWillExpire() {
|
||||
self.impl.serviceExtensionTimeWillExpire()
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <sqlcipher/sqlcipher.h>
|
||||
|
||||
|
||||
|
||||
@@ -1 +1,3 @@
|
||||
#import "Sync.h"
|
||||
#import "Sync.h"
|
||||
//#import <sqlcipher/sqlcipher.h>
|
||||
|
||||
|
||||
@@ -1,32 +1,95 @@
|
||||
//import SwiftSignalKit
|
||||
//import Postbox
|
||||
//import SyncCore
|
||||
//import BuildConfig
|
||||
import Foundation
|
||||
import SwiftSignalKit
|
||||
import ValueBox
|
||||
import MessageHistoryReadStateTable
|
||||
import MessageHistoryMetadataTable
|
||||
import PostboxDataTypes
|
||||
|
||||
@objc(SyncProviderImpl)
|
||||
final class SyncProviderImpl: NSObject {
|
||||
private func accountRecordIdPathName(_ id: Int64) -> String {
|
||||
return "account-\(UInt64(bitPattern: id))"
|
||||
}
|
||||
|
||||
/*@objc(SyncProviderImpl)
|
||||
final class SyncProviderImpl: NSObject, SyncProvider {
|
||||
func addIncomingMessage(withRootPath rootPath: String, accountId: Int64, encryptionParameters: DeviceSpecificEncryptionParameters, peerId: Int64, messageId: Int32, completion: ((Int32) -> Void)!) {
|
||||
let _ = (addIncomingMessageImpl(rootPath: rootPath, accountId: accountId, encryptionParameters: ValueBoxEncryptionParameters(forceEncryptionIfNoSet: false, key: ValueBoxEncryptionParameters.Key(data: encryptionParameters.key)!, salt: ValueBoxEncryptionParameters.Salt(data: encryptionParameters.salt)!), peerId: peerId, messageId: messageId)
|
||||
|> deliverOnMainQueue).start(next: { result in
|
||||
completion(Int32(clamping: result))
|
||||
})
|
||||
private final class ValueBoxLoggerImpl: ValueBoxLogger {
|
||||
func log(_ what: String) {
|
||||
print("ValueBox: \(what)")
|
||||
}
|
||||
}
|
||||
|
||||
private func addIncomingMessageImpl(rootPath: String, accountId: Int64, encryptionParameters: ValueBoxEncryptionParameters, peerId: Int64, messageId: Int32) -> Signal<Int, NoError> {
|
||||
return accountTransaction(rootPath: rootPath, id: AccountRecordId(rawValue: accountId), encryptionParameters: encryptionParameters, transaction: { transaction -> Int in
|
||||
transaction.countIncomingMessage(id: MessageId(peerId: PeerId(peerId), namespace: Namespaces.Message.Cloud, id: messageId))
|
||||
let totalUnreadState = transaction.getTotalUnreadState()
|
||||
let totalCount = totalUnreadState.count(for: .filtered, in: .chats, with: [
|
||||
.regularChatsAndPrivateGroups,
|
||||
.publicGroups,
|
||||
.channels
|
||||
])
|
||||
return Int(totalCount)
|
||||
})
|
||||
private extension PeerSummaryCounterTags {
|
||||
static let regularChatsAndPrivateGroups = PeerSummaryCounterTags(rawValue: 1 << 0)
|
||||
static let publicGroups = PeerSummaryCounterTags(rawValue: 1 << 1)
|
||||
static let channels = PeerSummaryCounterTags(rawValue: 1 << 2)
|
||||
}
|
||||
|
||||
private struct Namespaces {
|
||||
struct Message {
|
||||
static let Cloud: Int32 = 0
|
||||
}
|
||||
|
||||
struct Peer {
|
||||
static let CloudUser: Int32 = 0
|
||||
static let CloudGroup: Int32 = 1
|
||||
static let CloudChannel: Int32 = 2
|
||||
static let SecretChat: Int32 = 3
|
||||
}
|
||||
}
|
||||
|
||||
final class SyncProviderImpl {
|
||||
func addIncomingMessage(withRootPath rootPath: String, accountId: Int64, encryptionParameters: DeviceSpecificEncryptionParameters, peerId: Int64, messageId: Int32, completion: @escaping (Int32) -> Void) {
|
||||
Queue.mainQueue().async {
|
||||
let basePath = rootPath + "/" + accountRecordIdPathName(accountId) + "/postbox"
|
||||
|
||||
let valueBox = SqliteValueBox(basePath: basePath + "/db", queue: Queue.mainQueue(), logger: ValueBoxLoggerImpl(), encryptionParameters: ValueBoxEncryptionParameters(forceEncryptionIfNoSet: false, key: ValueBoxEncryptionParameters.Key(data: encryptionParameters.key)!, salt: ValueBoxEncryptionParameters.Salt(data: encryptionParameters.salt)!), disableCache: true, upgradeProgress: { _ in
|
||||
})
|
||||
|
||||
let metadataTable = MessageHistoryMetadataTable(valueBox: valueBox, table: MessageHistoryMetadataTable.tableSpec(10))
|
||||
let readStateTable = MessageHistoryReadStateTable(valueBox: valueBox, table: MessageHistoryReadStateTable.tableSpec(14), defaultMessageNamespaceReadStates: [:])
|
||||
|
||||
let peerId = PeerId(peerId)
|
||||
|
||||
let initialCombinedState = readStateTable.getCombinedState(peerId)
|
||||
let (combinedState, _) = readStateTable.addIncomingMessages(peerId, indices: Set([MessageIndex(id: MessageId(peerId: peerId, namespace: 0, id: messageId), timestamp: 1)]))
|
||||
if let combinedState = combinedState {
|
||||
let initialCount = initialCombinedState?.count ?? 0
|
||||
let updatedCount = combinedState.count
|
||||
let deltaCount = max(0, updatedCount - initialCount)
|
||||
|
||||
let tag: PeerSummaryCounterTags
|
||||
if peerId.namespace == Namespaces.Peer.CloudChannel {
|
||||
tag = .channels
|
||||
} else {
|
||||
tag = .regularChatsAndPrivateGroups
|
||||
}
|
||||
|
||||
var totalCount: Int32 = -1
|
||||
|
||||
var totalUnreadState = metadataTable.getChatListTotalUnreadState()
|
||||
if var counters = totalUnreadState.absoluteCounters[tag] {
|
||||
if initialCount == 0 && updatedCount > 0 {
|
||||
counters.chatCount += 1
|
||||
}
|
||||
counters.messageCount += deltaCount
|
||||
totalUnreadState.absoluteCounters[tag] = counters
|
||||
}
|
||||
if var counters = totalUnreadState.filteredCounters[tag] {
|
||||
if initialCount == 0 && updatedCount > 0 {
|
||||
counters.chatCount += 1
|
||||
}
|
||||
counters.messageCount += deltaCount
|
||||
totalUnreadState.filteredCounters[tag] = counters
|
||||
}
|
||||
|
||||
totalCount = totalUnreadState.count(for: .filtered, in: .messages, with: [.channels, .publicGroups, .regularChatsAndPrivateGroups])
|
||||
metadataTable.setChatListTotalUnreadState(totalUnreadState)
|
||||
metadataTable.setShouldReindexUnreadCounts(value: true)
|
||||
|
||||
metadataTable.beforeCommit()
|
||||
readStateTable.beforeCommit()
|
||||
|
||||
completion(totalCount)
|
||||
} else {
|
||||
completion(-1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user