mirror of https://github.com/oxen-io/session-ios
				
				
				
			
			You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			212 lines
		
	
	
		
			7.5 KiB
		
	
	
	
		
			Objective-C
		
	
			
		
		
	
	
			212 lines
		
	
	
		
			7.5 KiB
		
	
	
	
		
			Objective-C
		
	
//
 | 
						|
//  Copyright (c) 2018 Open Whisper Systems. All rights reserved.
 | 
						|
//
 | 
						|
 | 
						|
#import "ThreadViewHelper.h"
 | 
						|
#import <SignalServiceKit/AppContext.h>
 | 
						|
#import <SignalServiceKit/OWSPrimaryStorage.h>
 | 
						|
#import <SignalServiceKit/TSDatabaseView.h>
 | 
						|
#import <SignalServiceKit/TSThread.h>
 | 
						|
#import <YapDatabase/YapDatabase.h>
 | 
						|
#import <YapDatabase/YapDatabaseViewChange.h>
 | 
						|
#import <YapDatabase/YapDatabaseViewConnection.h>
 | 
						|
 | 
						|
NS_ASSUME_NONNULL_BEGIN
 | 
						|
 | 
						|
@interface ThreadViewHelper ()
 | 
						|
 | 
						|
@property (nonatomic) YapDatabaseConnection *uiDatabaseConnection;
 | 
						|
@property (nonatomic) YapDatabaseViewMappings *threadMappings;
 | 
						|
@property (nonatomic) BOOL shouldObserveDBModifications;
 | 
						|
 | 
						|
@end
 | 
						|
 | 
						|
#pragma mark -
 | 
						|
 | 
						|
@implementation ThreadViewHelper
 | 
						|
 | 
						|
- (instancetype)init
 | 
						|
{
 | 
						|
    self = [super init];
 | 
						|
    if (!self) {
 | 
						|
        return self;
 | 
						|
    }
 | 
						|
 | 
						|
    [self initializeMapping];
 | 
						|
 | 
						|
    return self;
 | 
						|
}
 | 
						|
 | 
						|
- (void)dealloc
 | 
						|
{
 | 
						|
    [[NSNotificationCenter defaultCenter] removeObserver:self];
 | 
						|
}
 | 
						|
 | 
						|
- (void)initializeMapping
 | 
						|
{
 | 
						|
    OWSAssertIsOnMainThread();
 | 
						|
 | 
						|
    NSString *grouping = TSInboxGroup;
 | 
						|
 | 
						|
    self.threadMappings =
 | 
						|
        [[YapDatabaseViewMappings alloc] initWithGroups:@[ grouping ] view:TSThreadDatabaseViewExtensionName];
 | 
						|
    [self.threadMappings setIsReversed:YES forGroup:grouping];
 | 
						|
 | 
						|
    self.uiDatabaseConnection = [OWSPrimaryStorage.sharedManager newDatabaseConnection];
 | 
						|
    [self.uiDatabaseConnection beginLongLivedReadTransaction];
 | 
						|
 | 
						|
    [[NSNotificationCenter defaultCenter] addObserver:self
 | 
						|
                                             selector:@selector(applicationDidBecomeActive:)
 | 
						|
                                                 name:OWSApplicationDidBecomeActiveNotification
 | 
						|
                                               object:nil];
 | 
						|
    [[NSNotificationCenter defaultCenter] addObserver:self
 | 
						|
                                             selector:@selector(applicationWillResignActive:)
 | 
						|
                                                 name:OWSApplicationWillResignActiveNotification
 | 
						|
                                               object:nil];
 | 
						|
 | 
						|
    [self updateShouldObserveDBModifications];
 | 
						|
}
 | 
						|
 | 
						|
- (void)applicationDidBecomeActive:(NSNotification *)notification
 | 
						|
{
 | 
						|
    [self updateShouldObserveDBModifications];
 | 
						|
}
 | 
						|
 | 
						|
- (void)applicationWillResignActive:(NSNotification *)notification
 | 
						|
{
 | 
						|
    [self updateShouldObserveDBModifications];
 | 
						|
}
 | 
						|
 | 
						|
- (void)updateShouldObserveDBModifications
 | 
						|
{
 | 
						|
    self.shouldObserveDBModifications = CurrentAppContext().isAppForegroundAndActive;
 | 
						|
}
 | 
						|
 | 
						|
// Don't observe database change notifications when the app is in the background.
 | 
						|
//
 | 
						|
// Instead, rebuild model state when app enters foreground.
 | 
						|
- (void)setShouldObserveDBModifications:(BOOL)shouldObserveDBModifications
 | 
						|
{
 | 
						|
    if (_shouldObserveDBModifications == shouldObserveDBModifications) {
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    _shouldObserveDBModifications = shouldObserveDBModifications;
 | 
						|
 | 
						|
    if (shouldObserveDBModifications) {
 | 
						|
        [self.uiDatabaseConnection beginLongLivedReadTransaction];
 | 
						|
        [self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
 | 
						|
            [self.threadMappings updateWithTransaction:transaction];
 | 
						|
        }];
 | 
						|
        [self updateThreads];
 | 
						|
        [self.delegate threadListDidChange];
 | 
						|
 | 
						|
        [[NSNotificationCenter defaultCenter] addObserver:self
 | 
						|
                                                 selector:@selector(yapDatabaseModified:)
 | 
						|
                                                     name:YapDatabaseModifiedNotification
 | 
						|
                                                   object:OWSPrimaryStorage.sharedManager.dbNotificationObject];
 | 
						|
        [[NSNotificationCenter defaultCenter] addObserver:self
 | 
						|
                                                 selector:@selector(yapDatabaseModifiedExternally:)
 | 
						|
                                                     name:YapDatabaseModifiedExternallyNotification
 | 
						|
                                                   object:nil];
 | 
						|
    } else {
 | 
						|
        [[NSNotificationCenter defaultCenter] removeObserver:self
 | 
						|
                                                        name:YapDatabaseModifiedNotification
 | 
						|
                                                      object:OWSPrimaryStorage.sharedManager.dbNotificationObject];
 | 
						|
        [[NSNotificationCenter defaultCenter] removeObserver:self
 | 
						|
                                                        name:YapDatabaseModifiedExternallyNotification
 | 
						|
                                                      object:nil];
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
#pragma mark - Database
 | 
						|
 | 
						|
- (YapDatabaseConnection *)uiDatabaseConnection
 | 
						|
{
 | 
						|
    OWSAssertIsOnMainThread();
 | 
						|
 | 
						|
    return _uiDatabaseConnection;
 | 
						|
}
 | 
						|
 | 
						|
- (void)yapDatabaseModifiedExternally:(NSNotification *)notification
 | 
						|
{
 | 
						|
    OWSAssertIsOnMainThread();
 | 
						|
 | 
						|
    DDLogVerbose(@"%@ %s", self.logTag, __PRETTY_FUNCTION__);
 | 
						|
 | 
						|
    if (self.shouldObserveDBModifications) {
 | 
						|
        // External database modifications can't be converted into incremental updates,
 | 
						|
        // so rebuild everything.  This is expensive and usually isn't necessary, but
 | 
						|
        // there's no alternative.
 | 
						|
        //
 | 
						|
        // We don't need to do this if we're not observing db modifications since we'll
 | 
						|
        // do it when we resume.
 | 
						|
        [self.uiDatabaseConnection beginLongLivedReadTransaction];
 | 
						|
        [self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
 | 
						|
            [self.threadMappings updateWithTransaction:transaction];
 | 
						|
        }];
 | 
						|
        
 | 
						|
        [self updateThreads];
 | 
						|
        [self.delegate threadListDidChange];
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
- (void)yapDatabaseModified:(NSNotification *)notification
 | 
						|
{
 | 
						|
    OWSAssertIsOnMainThread();
 | 
						|
 | 
						|
    DDLogVerbose(@"%@ %s", self.logTag, __PRETTY_FUNCTION__);
 | 
						|
 | 
						|
    NSArray *notifications = [self.uiDatabaseConnection beginLongLivedReadTransaction];
 | 
						|
 | 
						|
    if (!
 | 
						|
        [[self.uiDatabaseConnection ext:TSMessageDatabaseViewExtensionName] hasChangesForNotifications:notifications]) {
 | 
						|
        [self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
 | 
						|
            [self.threadMappings updateWithTransaction:transaction];
 | 
						|
        }];
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    NSArray *sectionChanges = nil;
 | 
						|
    NSArray *rowChanges = nil;
 | 
						|
    [[self.uiDatabaseConnection ext:TSThreadDatabaseViewExtensionName] getSectionChanges:§ionChanges
 | 
						|
                                                                              rowChanges:&rowChanges
 | 
						|
                                                                        forNotifications:notifications
 | 
						|
                                                                            withMappings:self.threadMappings];
 | 
						|
 | 
						|
    if (sectionChanges.count == 0 && rowChanges.count == 0) {
 | 
						|
        // Ignore irrelevant modifications.
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    [self updateThreads];
 | 
						|
 | 
						|
    [self.delegate threadListDidChange];
 | 
						|
}
 | 
						|
 | 
						|
- (void)updateThreads
 | 
						|
{
 | 
						|
    OWSAssertIsOnMainThread();
 | 
						|
 | 
						|
    NSMutableArray<TSThread *> *threads = [NSMutableArray new];
 | 
						|
    [self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
 | 
						|
        NSUInteger numberOfSections = [self.threadMappings numberOfSections];
 | 
						|
        OWSAssert(numberOfSections == 1);
 | 
						|
        for (NSUInteger section = 0; section < numberOfSections; section++) {
 | 
						|
            NSUInteger numberOfItems = [self.threadMappings numberOfItemsInSection:section];
 | 
						|
            for (NSUInteger item = 0; item < numberOfItems; item++) {
 | 
						|
                TSThread *thread = [[transaction extension:TSThreadDatabaseViewExtensionName]
 | 
						|
                    objectAtIndexPath:[NSIndexPath indexPathForItem:(NSInteger)item inSection:(NSInteger)section]
 | 
						|
                         withMappings:self.threadMappings];
 | 
						|
                [threads addObject:thread];
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }];
 | 
						|
 | 
						|
    _threads = [threads copy];
 | 
						|
}
 | 
						|
 | 
						|
@end
 | 
						|
 | 
						|
NS_ASSUME_NONNULL_END
 |