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.
		
		
		
		
		
			
		
			
				
	
	
		
			316 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Objective-C
		
	
			
		
		
	
	
			316 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Objective-C
		
	
| //
 | |
| //  Copyright (c) 2019 Open Whisper Systems. All rights reserved.
 | |
| //
 | |
| 
 | |
| #import "SelectThreadViewController.h"
 | |
| #import "ContactTableViewCell.h"
 | |
| #import "OWSSearchBar.h"
 | |
| #import "OWSTableViewController.h"
 | |
| #import "ThreadViewHelper.h"
 | |
| #import "UIColor+OWS.h"
 | |
| #import "UIFont+OWS.h"
 | |
| #import "UIView+OWS.h"
 | |
| #import <SignalUtilitiesKit/SignalUtilitiesKit-Swift.h>
 | |
| #import <SessionUtilitiesKit/NSString+SSK.h>
 | |
| #import <SignalUtilitiesKit/SignalAccount.h>
 | |
| #import <SessionMessagingKit/TSAccountManager.h>
 | |
| #import <SessionMessagingKit/TSContactThread.h>
 | |
| #import <SessionMessagingKit/TSThread.h>
 | |
| #import <YapDatabase/YapDatabase.h>
 | |
| #import <SessionUIKit/SessionUIKit.h>
 | |
| 
 | |
| NS_ASSUME_NONNULL_BEGIN
 | |
| 
 | |
| @interface SelectThreadViewController () <OWSTableViewControllerDelegate,
 | |
|     ThreadViewHelperDelegate,
 | |
|     UISearchBarDelegate>
 | |
| 
 | |
| @property (nonatomic, readonly) ContactsViewHelper *contactsViewHelper;
 | |
| @property (nonatomic, readonly) FullTextSearcher *fullTextSearcher;
 | |
| @property (nonatomic, readonly) ThreadViewHelper *threadViewHelper;
 | |
| @property (nonatomic, readonly) YapDatabaseConnection *uiDatabaseConnection;
 | |
| 
 | |
| @property (nonatomic, readonly) OWSTableViewController *tableViewController;
 | |
| 
 | |
| @property (nonatomic, readonly) UISearchBar *searchBar;
 | |
| 
 | |
| @end
 | |
| 
 | |
| #pragma mark -
 | |
| 
 | |
| @implementation SelectThreadViewController
 | |
| 
 | |
| - (void)loadView
 | |
| {
 | |
|     [super loadView];
 | |
| 
 | |
|     UIBarButtonItem *closeButton = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"X"] style:UIBarButtonItemStylePlain target:self action:@selector(dismissPressed:)];
 | |
|     closeButton.tintColor = LKColors.text;
 | |
|     self.navigationItem.leftBarButtonItem = closeButton;
 | |
|     
 | |
|     _fullTextSearcher = FullTextSearcher.shared;
 | |
|     _threadViewHelper = [ThreadViewHelper new];
 | |
|     _threadViewHelper.delegate = self;
 | |
| 
 | |
|     _uiDatabaseConnection = [[OWSPrimaryStorage sharedManager] newDatabaseConnection];
 | |
| #ifdef DEBUG
 | |
|     _uiDatabaseConnection.permittedTransactions = YDB_AnyReadTransaction;
 | |
| #endif
 | |
|     [_uiDatabaseConnection beginLongLivedReadTransaction];
 | |
|     [[NSNotificationCenter defaultCenter] addObserver:self
 | |
|                                              selector:@selector(yapDatabaseModified:)
 | |
|                                                  name:YapDatabaseModifiedNotification
 | |
|                                                object:OWSPrimaryStorage.sharedManager.dbNotificationObject];
 | |
|     [[NSNotificationCenter defaultCenter] addObserver:self
 | |
|                                              selector:@selector(yapDatabaseModifiedExternally:)
 | |
|                                                  name:YapDatabaseModifiedExternallyNotification
 | |
|                                                object:nil];
 | |
| 
 | |
|     [self createViews];
 | |
|     
 | |
|     // Loki: Set gradient background
 | |
|     self.tableViewController.tableView.backgroundColor = UIColor.clearColor;
 | |
|     self.tableViewController.view.backgroundColor = UIColor.clearColor;
 | |
|     CAGradientLayer *layer = [CAGradientLayer new];
 | |
|     layer.frame = UIScreen.mainScreen.bounds;
 | |
|     UIColor *gradientStartColor = LKAppModeUtilities.isLightMode ? [UIColor colorWithRGBHex:0xFCFCFC] : [UIColor colorWithRGBHex:0x171717];
 | |
|     UIColor *gradientEndColor = LKAppModeUtilities.isLightMode ? [UIColor colorWithRGBHex:0xFFFFFF] : [UIColor colorWithRGBHex:0x121212];
 | |
|     layer.colors = @[ (id)gradientStartColor.CGColor, (id)gradientEndColor.CGColor ];
 | |
|     [self.tableViewController.view.layer insertSublayer:layer atIndex:0];
 | |
|     
 | |
|     // Loki: Set navigation bar background color
 | |
|     UINavigationBar *navigationBar = self.navigationController.navigationBar;
 | |
|     [navigationBar setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
 | |
|     navigationBar.shadowImage = [UIImage new];
 | |
|     [navigationBar setTranslucent:NO];
 | |
|     navigationBar.barTintColor = LKColors.navigationBarBackground;
 | |
| 
 | |
|     [self updateTableContents];
 | |
| }
 | |
| 
 | |
| - (void)createViews
 | |
| {
 | |
|     OWSAssertDebug(self.selectThreadViewDelegate);
 | |
| 
 | |
|     // Table
 | |
|     _tableViewController = [OWSTableViewController new];
 | |
|     _tableViewController.delegate = self;
 | |
|     [self.view addSubview:self.tableViewController.view];
 | |
|     [self.tableViewController.view autoPinEdgeToSuperviewSafeArea:ALEdgeLeading];
 | |
|     [self.tableViewController.view autoPinEdgeToSuperviewSafeArea:ALEdgeTrailing];
 | |
|     [_tableViewController.view autoPinEdgeToSuperviewEdge:ALEdgeTop];
 | |
|     [_tableViewController.view autoPinEdgeToSuperviewEdge:ALEdgeBottom];
 | |
|     self.tableViewController.tableView.rowHeight = UITableViewAutomaticDimension;
 | |
|     self.tableViewController.tableView.estimatedRowHeight = 60;
 | |
|     BOOL isIphone6OrSmaller = (UIScreen.mainScreen.bounds.size.height - 667) < 1;
 | |
|     CGFloat bottomInset = isIphone6OrSmaller ? LKValues.mediumSpacing : 34.0f;
 | |
|     self.tableViewController.tableView.contentInset = UIEdgeInsetsMake(0, 0, bottomInset, 0);
 | |
| }
 | |
| 
 | |
| - (void)yapDatabaseModifiedExternally:(NSNotification *)notification
 | |
| {
 | |
|     OWSAssertIsOnMainThread();
 | |
| 
 | |
|     OWSLogVerbose(@"");
 | |
| 
 | |
|     [self.uiDatabaseConnection beginLongLivedReadTransaction];
 | |
|     [self updateTableContents];
 | |
| }
 | |
| 
 | |
| - (void)yapDatabaseModified:(NSNotification *)notification
 | |
| {
 | |
|     OWSAssertIsOnMainThread();
 | |
|     
 | |
|     [self.uiDatabaseConnection beginLongLivedReadTransaction];
 | |
|     [self updateTableContents];
 | |
| }
 | |
| 
 | |
| #pragma mark - UISearchBarDelegate
 | |
| 
 | |
| - (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
 | |
| {
 | |
|     [self updateTableContents];
 | |
| }
 | |
| 
 | |
| - (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
 | |
| {
 | |
|     [self updateTableContents];
 | |
| }
 | |
| 
 | |
| - (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar
 | |
| {
 | |
|     [self updateTableContents];
 | |
| }
 | |
| 
 | |
| - (void)searchBarResultsListButtonClicked:(UISearchBar *)searchBar
 | |
| {
 | |
|     [self updateTableContents];
 | |
| }
 | |
| 
 | |
| - (void)searchBar:(UISearchBar *)searchBar selectedScopeButtonIndexDidChange:(NSInteger)selectedScope
 | |
| {
 | |
|     [self updateTableContents];
 | |
| }
 | |
| 
 | |
| #pragma mark - Table Contents
 | |
| 
 | |
| - (void)updateTableContents
 | |
| {
 | |
|     __weak SelectThreadViewController *weakSelf = self;
 | |
|     ContactsViewHelper *helper = self.contactsViewHelper;
 | |
|     OWSTableContents *contents = [OWSTableContents new];
 | |
| 
 | |
|     // Existing threads are listed first, ordered by most recently active
 | |
|     OWSTableSection *recentChatsSection = [OWSTableSection new];
 | |
|     recentChatsSection.headerTitle = NSLocalizedString(@"SELECT_THREAD_TABLE_RECENT_CHATS_TITLE", @"");
 | |
|     for (TSThread *thread in self.threadViewHelper.threads) {
 | |
|         [recentChatsSection
 | |
|             addItem:[OWSTableItem
 | |
|                         itemWithCustomCellBlock:^{
 | |
|                             SelectThreadViewController *strongSelf = weakSelf;
 | |
|                             OWSCAssertDebug(strongSelf);
 | |
| 
 | |
|                             // To be consistent with the threads (above), we use ContactTableViewCell
 | |
|                             // instead of HomeViewCell to present contacts and threads.
 | |
|                             ContactTableViewCell *cell = [ContactTableViewCell new];
 | |
| 
 | |
|                             BOOL isBlocked = [SSKEnvironment.shared.blockingManager isThreadBlocked:thread];
 | |
|                             if (isBlocked) {
 | |
|                                 cell.accessoryMessage = NSLocalizedString(
 | |
|                                     @"CONTACT_CELL_IS_BLOCKED", @"An indicator that a contact has been blocked.");
 | |
|                             }
 | |
| 
 | |
|                             [cell configureWithThread:thread];
 | |
| 
 | |
|                             if (!cell.hasAccessoryText) {
 | |
|                                 // Don't add a disappearing messages indicator if we've already added a "blocked" label.
 | |
|                                 __block OWSDisappearingMessagesConfiguration *disappearingMessagesConfiguration;
 | |
|                                 [self.uiDatabaseConnection
 | |
|                                     readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) {
 | |
|                                         disappearingMessagesConfiguration = [OWSDisappearingMessagesConfiguration
 | |
|                                             fetchObjectWithUniqueID:thread.uniqueId
 | |
|                                                         transaction:transaction];
 | |
|                                     }];
 | |
| 
 | |
|                                 if (disappearingMessagesConfiguration && disappearingMessagesConfiguration.isEnabled) {
 | |
|                                     DisappearingTimerConfigurationView *disappearingTimerConfigurationView =
 | |
|                                         [[DisappearingTimerConfigurationView alloc]
 | |
|                                             initWithDurationSeconds:disappearingMessagesConfiguration.durationSeconds];
 | |
| 
 | |
|                                     disappearingTimerConfigurationView.tintColor = LKColors.text;
 | |
|                                     [disappearingTimerConfigurationView autoSetDimensionsToSize:CGSizeMake(44, 44)];
 | |
| 
 | |
|                                     [cell ows_setAccessoryView:disappearingTimerConfigurationView];
 | |
|                                 }
 | |
|                             }
 | |
| 
 | |
|                             return cell;
 | |
|                         }
 | |
|                         customRowHeight:UITableViewAutomaticDimension
 | |
|                         actionBlock:^{
 | |
|                             typeof(self) strongSelf = weakSelf;
 | |
|                             if (!strongSelf) {
 | |
|                                 return;
 | |
|                             }
 | |
| 
 | |
|                             BOOL isBlocked = [SSKEnvironment.shared.blockingManager isThreadBlocked:thread];
 | |
|                             if (isBlocked && ![strongSelf.selectThreadViewDelegate canSelectBlockedContact]) {
 | |
|                                 [BlockListUIUtils
 | |
|                                     showUnblockThreadActionSheet:thread
 | |
|                                               fromViewController:strongSelf
 | |
|                                                  blockingManager:SSKEnvironment.shared.blockingManager
 | |
|                                                  completionBlock:^(BOOL isStillBlocked) {
 | |
|                                                      if (!isStillBlocked) {
 | |
|                                                          [strongSelf.selectThreadViewDelegate threadWasSelected:thread];
 | |
|                                                      }
 | |
|                                                  }];
 | |
|                                 return;
 | |
|                             }
 | |
| 
 | |
|                             [strongSelf.selectThreadViewDelegate threadWasSelected:thread];
 | |
|                         }]];
 | |
|     }
 | |
| 
 | |
|     if (recentChatsSection.itemCount > 0) {
 | |
|         [contents addSection:recentChatsSection];
 | |
|     }
 | |
| 
 | |
|     if (recentChatsSection.itemCount < 1) {
 | |
|         OWSTableSection *emptySection = [OWSTableSection new];
 | |
|         [emptySection
 | |
|             addItem:[OWSTableItem
 | |
|                         softCenterLabelItemWithText:NSLocalizedString(@"SETTINGS_BLOCK_LIST_NO_CONTACTS",
 | |
|                                                         @"A label that indicates the user has no Signal contacts.")]];
 | |
|         [contents addSection:emptySection];
 | |
|     }
 | |
| 
 | |
|     self.tableViewController.contents = contents;
 | |
| }
 | |
| 
 | |
| - (void)signalAccountWasSelected:(SignalAccount *)signalAccount
 | |
| {
 | |
|     OWSAssertDebug(signalAccount);
 | |
|     OWSAssertDebug(self.selectThreadViewDelegate);
 | |
| 
 | |
|     if ([SSKEnvironment.shared.blockingManager isRecipientIdBlocked:signalAccount.recipientId]
 | |
|         && ![self.selectThreadViewDelegate canSelectBlockedContact]) {
 | |
| 
 | |
|         __weak SelectThreadViewController *weakSelf = self;
 | |
|         [BlockListUIUtils showUnblockSignalAccountActionSheet:signalAccount
 | |
|                                            fromViewController:self
 | |
|                                               blockingManager:SSKEnvironment.shared.blockingManager
 | |
|                                               completionBlock:^(BOOL isBlocked) {
 | |
|                                                   if (!isBlocked) {
 | |
|                                                       [weakSelf signalAccountWasSelected:signalAccount];
 | |
|                                                   }
 | |
|                                               }];
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     __block TSThread *thread = nil;
 | |
|     [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
 | |
|         thread = [TSContactThread getOrCreateThreadWithContactSessionID:signalAccount.recipientId transaction:transaction];
 | |
|     }];
 | |
|     OWSAssertDebug(thread);
 | |
| 
 | |
|     [self.selectThreadViewDelegate threadWasSelected:thread];
 | |
| }
 | |
| 
 | |
| #pragma mark - Events
 | |
| 
 | |
| - (void)dismissPressed:(id)sender
 | |
| {
 | |
|     [self.searchBar resignFirstResponder];
 | |
|     [self dismissViewControllerAnimated:YES completion:nil];
 | |
| }
 | |
| 
 | |
| #pragma mark - OWSTableViewControllerDelegate
 | |
| 
 | |
| - (void)tableViewWillBeginDragging
 | |
| {
 | |
|     [self.searchBar resignFirstResponder];
 | |
| }
 | |
| 
 | |
| #pragma mark - ThreadViewHelperDelegate
 | |
| 
 | |
| - (void)threadListDidChange
 | |
| {
 | |
|     [self updateTableContents];
 | |
| }
 | |
| 
 | |
| #pragma mark - ContactsViewHelperDelegate
 | |
| 
 | |
| - (void)contactsViewHelperDidUpdateContacts
 | |
| {
 | |
|     [self updateTableContents];
 | |
| }
 | |
| 
 | |
| - (BOOL)shouldHideLocalNumber
 | |
| {
 | |
|     return NO;
 | |
| }
 | |
| 
 | |
| @end
 | |
| 
 | |
| NS_ASSUME_NONNULL_END
 |