|
|
|
@ -3,47 +3,25 @@
|
|
|
|
|
#import "FunctionalUtil.h"
|
|
|
|
|
#import "ObservableValue.h"
|
|
|
|
|
#import "PreferencesUtil.h"
|
|
|
|
|
#import "NSDate+millisecondTimeStamp.h"
|
|
|
|
|
#import "TSCall.h"
|
|
|
|
|
#import "TSStorageManager.h"
|
|
|
|
|
#import "TSContactThread.h"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define RECENT_CALLS_DEFAULT_KEY @"RPRecentCallsDefaultKey"
|
|
|
|
|
|
|
|
|
|
typedef BOOL (^SearchTermConditionalBlock)(RecentCall*, NSUInteger, BOOL*);
|
|
|
|
|
|
|
|
|
|
@interface RecentCallManager () {
|
|
|
|
|
NSMutableArray *_allRecents;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@interface RecentCallManager ()
|
|
|
|
|
@property YapDatabaseConnection *dbConnection;
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@implementation RecentCallManager
|
|
|
|
|
|
|
|
|
|
- (id)init {
|
|
|
|
|
if (self = [super init]) {
|
|
|
|
|
[self initRecentCallsObservable];
|
|
|
|
|
}
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
- (instancetype)init{
|
|
|
|
|
self = [super init];
|
|
|
|
|
|
|
|
|
|
-(void) initRecentCallsObservable {
|
|
|
|
|
_allRecents = [self loadContactsFromDefaults];
|
|
|
|
|
observableRecentsController = [ObservableValueController observableValueControllerWithInitialValue:_allRecents];
|
|
|
|
|
if (self) {
|
|
|
|
|
_dbConnection = [TSStorageManager sharedManager].newDatabaseConnection;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (ObservableValue *)getObservableRecentCalls {
|
|
|
|
|
return observableRecentsController;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
-(void) watchForContactUpdatesFrom:(ContactsManager*) contactManager untillCancelled:(TOCCancelToken*) cancelToken{
|
|
|
|
|
[contactManager.getObservableRedPhoneUsers watchLatestValue:^(NSArray* latestUsers) {
|
|
|
|
|
for (RecentCall* recentCall in _allRecents) {
|
|
|
|
|
if (![contactManager latestContactWithRecordId:recentCall.contactRecordID]) {
|
|
|
|
|
Contact* contact = [contactManager latestContactForPhoneNumber:recentCall.phoneNumber];
|
|
|
|
|
if(contact){
|
|
|
|
|
[self updateRecentCall:recentCall withContactId:contact.recordID];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} onThread:NSThread.mainThread untilCancelled:cancelToken];
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)watchForCallsThrough:(PhoneManager*)phoneManager
|
|
|
|
@ -54,7 +32,7 @@ typedef BOOL (^SearchTermConditionalBlock)(RecentCall*, NSUInteger, BOOL*);
|
|
|
|
|
if (latestCall != nil) {
|
|
|
|
|
[self addCall:latestCall];
|
|
|
|
|
}
|
|
|
|
|
} onThread:NSThread.mainThread untilCancelled:untilCancelledToken];
|
|
|
|
|
} onThread:NSThread.currentThread untilCancelled:untilCancelledToken];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)addCall:(CallState*)call {
|
|
|
|
@ -93,92 +71,11 @@ typedef BOOL (^SearchTermConditionalBlock)(RecentCall*, NSUInteger, BOOL*);
|
|
|
|
|
andCallType:RPRecentCallTypeMissed]];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
-(void) updateRecentCall:(RecentCall*) recentCall withContactId:(ABRecordID) contactId {
|
|
|
|
|
[recentCall updateRecentCallWithContactId:contactId];
|
|
|
|
|
[observableRecentsController updateValue:_allRecents.copy];
|
|
|
|
|
[self saveContactsToDefaults];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)addRecentCall:(RecentCall*)recentCall {
|
|
|
|
|
[_allRecents insertObject:recentCall atIndex:0];
|
|
|
|
|
[observableRecentsController updateValue:_allRecents.copy];
|
|
|
|
|
[self saveContactsToDefaults];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)removeRecentCall:(RecentCall *)recentCall {
|
|
|
|
|
[_allRecents removeObject:recentCall];
|
|
|
|
|
[observableRecentsController updateValue:_allRecents.copy];
|
|
|
|
|
[self saveContactsToDefaults];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)archiveRecentCall:(RecentCall *)recentCall {
|
|
|
|
|
NSUInteger indexOfRecent = [_allRecents indexOfObject:recentCall];
|
|
|
|
|
recentCall.isArchived = YES;
|
|
|
|
|
_allRecents[indexOfRecent] = recentCall;
|
|
|
|
|
[self saveContactsToDefaults];
|
|
|
|
|
[observableRecentsController updateValue:_allRecents.copy];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)clearRecentCalls {
|
|
|
|
|
[_allRecents removeAllObjects];
|
|
|
|
|
[observableRecentsController updateValue:_allRecents.copy];
|
|
|
|
|
[self saveContactsToDefaults];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)saveContactsToDefaults {
|
|
|
|
|
NSUserDefaults *defaults = NSUserDefaults.standardUserDefaults;
|
|
|
|
|
NSData *saveData = [NSKeyedArchiver archivedDataWithRootObject:_allRecents.copy];
|
|
|
|
|
|
|
|
|
|
[defaults setObject:saveData forKey:RECENT_CALLS_DEFAULT_KEY];
|
|
|
|
|
[defaults synchronize];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSMutableArray *)loadContactsFromDefaults {
|
|
|
|
|
NSUserDefaults *defaults = NSUserDefaults.standardUserDefaults;
|
|
|
|
|
NSData *encodedData = [defaults objectForKey:RECENT_CALLS_DEFAULT_KEY];
|
|
|
|
|
id data = [NSKeyedUnarchiver unarchiveObjectWithData:encodedData];
|
|
|
|
|
|
|
|
|
|
if(![data isKindOfClass:NSArray.class]) {
|
|
|
|
|
return [NSMutableArray array];
|
|
|
|
|
} else {
|
|
|
|
|
return [NSMutableArray arrayWithArray:data];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSArray *)recentsForSearchString:(NSString *)optionalSearchString andExcludeArchived:(BOOL)excludeArchived {
|
|
|
|
|
ContactsManager *contactsManager = Environment.getCurrent.contactsManager;
|
|
|
|
|
SearchTermConditionalBlock searchBlock = ^BOOL(RecentCall *obj, NSUInteger idx, BOOL *stop) {
|
|
|
|
|
BOOL nameMatchesSearch = YES;
|
|
|
|
|
BOOL numberMatchesSearch = YES;
|
|
|
|
|
|
|
|
|
|
if (optionalSearchString) {
|
|
|
|
|
NSString *contactName = [contactsManager latestContactWithRecordId:obj.contactRecordID].fullName;
|
|
|
|
|
nameMatchesSearch = [ContactsManager name:contactName matchesQuery:optionalSearchString];
|
|
|
|
|
numberMatchesSearch = [ContactsManager phoneNumber:obj.phoneNumber matchesQuery:optionalSearchString];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (excludeArchived) {
|
|
|
|
|
return !obj.isArchived && (nameMatchesSearch || numberMatchesSearch);
|
|
|
|
|
} else {
|
|
|
|
|
return (nameMatchesSearch || numberMatchesSearch);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
NSIndexSet *newsFeedIndexes = [_allRecents indexesOfObjectsPassingTest:searchBlock];
|
|
|
|
|
return [_allRecents objectsAtIndexes:newsFeedIndexes];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSUInteger)missedCallCount {
|
|
|
|
|
SearchTermConditionalBlock missedCallBlock = ^BOOL(RecentCall *recentCall, NSUInteger idx, BOOL *stop) {
|
|
|
|
|
return !recentCall.userNotified;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return [[_allRecents indexesOfObjectsPassingTest:missedCallBlock] count];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
-(BOOL) isPhoneNumberPresentInRecentCalls:(PhoneNumber*) phoneNumber {
|
|
|
|
|
return [_allRecents any:^int(RecentCall* call) {
|
|
|
|
|
return [call.phoneNumber resolvesInternationallyTo:phoneNumber];
|
|
|
|
|
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
|
|
|
|
TSContactThread *thread = [TSContactThread getOrCreateThreadWithContactId:recentCall.phoneNumber.toE164 transaction:transaction];
|
|
|
|
|
TSCall *call = [[TSCall alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp] withCallNumber:recentCall.phoneNumber.toE164 callType:recentCall.callType inThread:thread];
|
|
|
|
|
[call saveWithTransaction:transaction];
|
|
|
|
|
}];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|