session-ios/SignalUtilitiesKit/Sharing/SelectThreadViewController.m

317 lines
13 KiB
Objective-C

//
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
//
#import "SelectThreadViewController.h"
#import "BlockListUIUtils.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 getOrCreateThreadWithContactId: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