mirror of
https://github.com/danog/Telegram.git
synced 2024-12-02 09:27:55 +01:00
2129 lines
78 KiB
Plaintext
2129 lines
78 KiB
Plaintext
#import "TGDialogListController.h"
|
|
|
|
#import "Freedom.h"
|
|
|
|
#import "TGDialogListCompanion.h"
|
|
#import "TGPeerIdAdapter.h"
|
|
|
|
#import "TGSearchDisplayMixin.h"
|
|
|
|
#import "TGConversation.h"
|
|
#import "TGUser.h"
|
|
#import "TGMessage.h"
|
|
|
|
#import "TGListsTableView.h"
|
|
|
|
#import "SGraphObjectNode.h"
|
|
|
|
#import "TGRemoteImageView.h"
|
|
|
|
#import "TGDialogListCell.h"
|
|
#import "TGDialogListSearchCell.h"
|
|
|
|
#import "TGToolbarButton.h"
|
|
|
|
#import "TGActionTableView.h"
|
|
|
|
#import "TGHacks.h"
|
|
#import "TGSearchBar.h"
|
|
#import "TGImageUtils.h"
|
|
#import "TGLabel.h"
|
|
|
|
#import "TGObserverProxy.h"
|
|
|
|
#import <QuartzCore/QuartzCore.h>
|
|
#import <objc/runtime.h>
|
|
|
|
#import "TGActivityIndicatorView.h"
|
|
|
|
#import "TGModernBarButton.h"
|
|
|
|
#import "TGFont.h"
|
|
|
|
#import "TGDialogListBroadcastsMenuCell.h"
|
|
|
|
#import "TGGlobalMessageSearchSignals.h"
|
|
|
|
#import "TGLockIconView.h"
|
|
|
|
#import "TGDatabase.h"
|
|
#import "TGAppDelegate.h"
|
|
|
|
#import "TGDialogListTitleContainer.h"
|
|
|
|
#import "TGHashtagPanelCell.h"
|
|
|
|
#import "TGMenuView.h"
|
|
|
|
#import "TGInterfaceManager.h"
|
|
|
|
#import "TGModernConversationController.h"
|
|
|
|
#include <map>
|
|
#include <set>
|
|
|
|
static bool _debugDoNotJump = false;
|
|
|
|
static int64_t lastAppearedConversationId = 0;
|
|
|
|
#pragma mark -
|
|
|
|
@interface TGDialogListController () <TGViewControllerNavigationBarAppearance, UITableViewDelegate, UITableViewDataSource, UIActionSheetDelegate, TGSearchDisplayMixinDelegate>
|
|
{
|
|
std::map<int64_t, NSString *> _usersTypingInConversation;
|
|
|
|
UIView *_headerBackgroundView;
|
|
|
|
NSArray *_reusableSectionHeaders;
|
|
|
|
SMetaDisposable *_searchDisposable;
|
|
NSString *_searchResultsQuery;
|
|
|
|
SMetaDisposable *_recentSearchResultsDisposable;
|
|
|
|
bool _didSelectMessage;
|
|
|
|
TGMenuContainerView *_menuContainerView;
|
|
}
|
|
|
|
@property (nonatomic, strong) TGSearchBar *searchBar;
|
|
@property (nonatomic, strong) TGSearchDisplayMixin *searchMixin;
|
|
@property (nonatomic) bool searchControllerWasLoaded;
|
|
|
|
@property (nonatomic, strong) UITableView *tableView;
|
|
@property (nonatomic) bool editingMode;
|
|
@property (nonatomic) CGFloat draggingStartOffset;
|
|
|
|
@property (nonatomic, strong) NSMutableArray *listModel;
|
|
|
|
@property (nonatomic, strong) NSArray *searchResultsSections;
|
|
@property (nonatomic, strong) NSArray *recentSearchResultsSections;
|
|
|
|
@property (nonatomic) bool isLoading;
|
|
|
|
@property (nonatomic, strong) TGDialogListTitleContainer *titleContainer;
|
|
@property (nonatomic, strong) UILabel *titleStatusLabel;
|
|
@property (nonatomic, strong) UILabel *titleLabel;
|
|
@property (nonatomic, strong) TGLockIconView *titleLockIconView;
|
|
|
|
@property (nonatomic, strong) UIActivityIndicatorView *titleStatusIndicator;
|
|
|
|
@property (nonatomic) int64_t conversationIdToDelete;
|
|
|
|
@property (nonatomic, strong) UIActionSheet *currentActionSheet;
|
|
|
|
@property (nonatomic, strong) UIView *emptyListContainer;
|
|
|
|
@property (nonatomic, strong) TGObserverProxy *significantTimeChangeProxy;
|
|
@property (nonatomic, strong) TGObserverProxy *didEnterBackgroundProxy;
|
|
@property (nonatomic, strong) TGObserverProxy *willEnterForegroundProxy;
|
|
|
|
@end
|
|
|
|
NSString *authorNameYou = @" __TGLocalized__YOU";
|
|
|
|
@implementation TGDialogListController
|
|
|
|
+ (void)setLastAppearedConversationId:(int64_t)conversationId
|
|
{
|
|
lastAppearedConversationId = conversationId;
|
|
}
|
|
|
|
+ (void)setDebugDoNotJump:(bool)debugDoNotJump
|
|
{
|
|
_debugDoNotJump = debugDoNotJump;
|
|
}
|
|
|
|
+ (bool)debugDoNotJump
|
|
{
|
|
return _debugDoNotJump;
|
|
}
|
|
|
|
- (id)initWithCompanion:(TGDialogListCompanion *)companion
|
|
{
|
|
self = [super initWithNibName:nil bundle:nil];
|
|
if (self)
|
|
{
|
|
self.automaticallyManageScrollViewInsets = true;
|
|
self.ignoreKeyboardWhenAdjustingScrollViewInsets = true;
|
|
|
|
_actionHandle = [[ASHandle alloc] initWithDelegate:self releaseOnMainThread:true];
|
|
|
|
_listModel = [[NSMutableArray alloc] init];
|
|
|
|
_reusableSectionHeaders = [[NSArray alloc] initWithObjects:[[NSMutableArray alloc] init], [[NSMutableArray alloc] init], nil];
|
|
|
|
_dialogListCompanion = companion;
|
|
_dialogListCompanion.dialogListController = self;
|
|
|
|
_significantTimeChangeProxy = [[TGObserverProxy alloc] initWithTarget:self targetSelector:@selector(significantTimeChange:) name:UIApplicationSignificantTimeChangeNotification];
|
|
_didEnterBackgroundProxy = [[TGObserverProxy alloc] initWithTarget:self targetSelector:@selector(didEnterBackground:) name:UIApplicationDidEnterBackgroundNotification];
|
|
_willEnterForegroundProxy = [[TGObserverProxy alloc] initWithTarget:self targetSelector:@selector(willEnterForeground:) name:UIApplicationWillEnterForegroundNotification];
|
|
|
|
_doNotHideSearchAutomatically = [[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad;
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (void)dealloc
|
|
{
|
|
[_actionHandle reset];
|
|
[ActionStageInstance() removeWatcher:self];
|
|
|
|
_dialogListCompanion.dialogListController = nil;
|
|
|
|
[self doUnloadView];
|
|
|
|
_currentActionSheet.delegate = nil;
|
|
}
|
|
|
|
- (void)_loadStatusViews
|
|
{
|
|
if (_titleStatusLabel == nil)
|
|
{
|
|
_titleStatusLabel = [[UILabel alloc] init];
|
|
_titleStatusLabel.clipsToBounds = false;
|
|
_titleStatusLabel.backgroundColor = [UIColor clearColor];
|
|
_titleStatusLabel.textColor = [UIColor blackColor];
|
|
_titleStatusLabel.font = TGBoldSystemFontOfSize(16.0f);
|
|
[_titleContainer addSubview:_titleStatusLabel];
|
|
|
|
_titleStatusIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
|
|
[_titleContainer addSubview:_titleStatusIndicator];
|
|
}
|
|
}
|
|
|
|
- (UIBarButtonItem *)controllerLeftBarButtonItem
|
|
{
|
|
if (![_dialogListCompanion showListEditingControl])
|
|
return nil;
|
|
|
|
if (!_editingMode)
|
|
{
|
|
return [[UIBarButtonItem alloc] initWithTitle:TGLocalized(@"Common.Edit") style:UIBarButtonItemStylePlain target:self action:@selector(editButtonPressed)];
|
|
}
|
|
else
|
|
{
|
|
return [[UIBarButtonItem alloc] initWithTitle:TGLocalized(@"Common.Done") style:UIBarButtonItemStyleDone target:self action:@selector(doneButtonPressed)];
|
|
}
|
|
|
|
return nil;
|
|
}
|
|
|
|
- (void)scrollToTopRequested
|
|
{
|
|
[_tableView setContentOffset:CGPointMake(0, -_tableView.contentInset.top) animated:true];
|
|
}
|
|
|
|
- (void)titleStateUpdated:(NSString *)text isLoading:(bool)__unused isLoading
|
|
{
|
|
if (text == nil)
|
|
{
|
|
_titleStatusLabel.hidden = true;
|
|
_titleStatusIndicator.hidden = true;
|
|
_titleLabel.hidden = false;
|
|
_titleLockIconView.hidden = false;
|
|
|
|
[_titleStatusIndicator stopAnimating];
|
|
}
|
|
else
|
|
{
|
|
[self _loadStatusViews];
|
|
|
|
_titleStatusLabel.hidden = false;
|
|
_titleStatusIndicator.hidden = false;
|
|
_titleLabel.hidden = true;
|
|
_titleLockIconView.hidden = true;
|
|
|
|
_titleStatusLabel.text = text;
|
|
[_titleStatusLabel sizeToFit];
|
|
|
|
[self _layoutTitleViews:self.interfaceOrientation];
|
|
|
|
if (!_titleStatusIndicator.isAnimating)
|
|
[_titleStatusIndicator startAnimating];
|
|
}
|
|
}
|
|
|
|
- (void)updateDatabasePassword
|
|
{
|
|
_titleLockIconView.alpha = [TGDatabaseInstance() isPasswordSet:NULL] ? 1.0f : 0.0f;
|
|
if (_titleLockIconView.isLocked != [TGAppDelegateInstance isManuallyLocked])
|
|
[_titleLockIconView setIsLocked:[TGAppDelegateInstance isManuallyLocked] animated:false];
|
|
[self _layoutTitleViews:self.interfaceOrientation];
|
|
}
|
|
|
|
- (void)userTypingInConversationUpdated:(int64_t)conversationId typingString:(NSString *)typingString
|
|
{
|
|
bool updated = false;
|
|
|
|
if (typingString.length != 0)
|
|
{
|
|
std::map<int64_t, NSString *>::iterator conversationIt = _usersTypingInConversation.find(conversationId);
|
|
|
|
if (conversationIt == _usersTypingInConversation.end())
|
|
{
|
|
updated = true;
|
|
_usersTypingInConversation.insert(std::pair<int64_t, NSString *>(conversationId, typingString));
|
|
}
|
|
else
|
|
{
|
|
if (![conversationIt->second isEqualToString:typingString])
|
|
{
|
|
updated = true;
|
|
_usersTypingInConversation[conversationId] = typingString;
|
|
}
|
|
}
|
|
}
|
|
else if (typingString.length == 0 && _usersTypingInConversation.find(conversationId) != _usersTypingInConversation.end())
|
|
{
|
|
updated = true;
|
|
_usersTypingInConversation.erase(conversationId);
|
|
}
|
|
|
|
if (updated)
|
|
{
|
|
Class dialogListCellClass = [TGDialogListCell class];
|
|
for (UITableViewCell *cell in [_tableView visibleCells])
|
|
{
|
|
if ([cell isKindOfClass:dialogListCellClass])
|
|
{
|
|
TGDialogListCell *dialogCell = (TGDialogListCell *)cell;
|
|
if (dialogCell.conversationId == conversationId)
|
|
{
|
|
[dialogCell setTypingString:typingString animated:true];
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
- (UIBarButtonItem *)controllerRightBarButtonItem
|
|
{
|
|
if (_editingMode)
|
|
return nil;
|
|
|
|
if (iosMajorVersion() < 7)
|
|
{
|
|
TGModernBarButton *composeButton = [[TGModernBarButton alloc] initWithImage:[UIImage imageNamed:@"ModernNavigationComposeButtonIcon.png"]];
|
|
composeButton.portraitAdjustment = CGPointMake(-7, -5);
|
|
composeButton.landscapeAdjustment = CGPointMake(-7, -4);
|
|
[composeButton addTarget:self action:@selector(composeMessageButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
|
|
return [[UIBarButtonItem alloc] initWithCustomView:composeButton];
|
|
}
|
|
|
|
return [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCompose target:self action:@selector(composeMessageButtonPressed:)];
|
|
}
|
|
|
|
- (UIBarStyle)requiredNavigationBarStyle
|
|
{
|
|
return UIBarStyleDefault;
|
|
}
|
|
|
|
- (void)_layoutTitleViews:(UIInterfaceOrientation)orientation
|
|
{
|
|
CGFloat portraitOffset = 0.0f;
|
|
CGFloat landscapeOffset = 0.0f;
|
|
CGFloat indicatorOffset = 0.0f;
|
|
if (iosMajorVersion() >= 7)
|
|
{
|
|
portraitOffset = 1.0f;
|
|
landscapeOffset = 0.0f;
|
|
indicatorOffset = -1.0f;
|
|
}
|
|
else
|
|
{
|
|
portraitOffset = -1.0f;
|
|
landscapeOffset = 1.0f;
|
|
indicatorOffset = 0.0f;
|
|
}
|
|
|
|
CGRect titleLabelFrame = _titleLabel.frame;
|
|
titleLabelFrame.origin = CGPointMake(CGFloor((_titleContainer.frame.size.width - titleLabelFrame.size.width) / 2.0f), CGFloor((_titleContainer.frame.size.height - titleLabelFrame.size.height) / 2.0f) + (UIInterfaceOrientationIsPortrait(orientation) ? portraitOffset : landscapeOffset));
|
|
if (_titleLockIconView.alpha > FLT_EPSILON)
|
|
titleLabelFrame.origin.x -= 4.0f;
|
|
_titleLockIconView.frame = CGRectMake(CGRectGetMaxX(titleLabelFrame) + 6.0f, titleLabelFrame.origin.y + 4.0f, _titleLockIconView.frame.size.width, _titleLockIconView.frame.size.height);
|
|
_titleLabel.frame = titleLabelFrame;
|
|
|
|
if (_titleStatusLabel != nil)
|
|
{
|
|
CGRect titleStatusLabelFrame = _titleStatusLabel.frame;
|
|
titleStatusLabelFrame.origin = CGPointMake(CGFloor((_titleContainer.frame.size.width - titleStatusLabelFrame.size.width) / 2.0f) + 16.0f, CGFloor((_titleContainer.frame.size.height - titleStatusLabelFrame.size.height) / 2.0f) + (UIInterfaceOrientationIsPortrait(orientation) ? portraitOffset : landscapeOffset));
|
|
_titleStatusLabel.frame = titleStatusLabelFrame;
|
|
|
|
CGRect titleIndicatorFrame = _titleStatusIndicator.frame;
|
|
titleIndicatorFrame.origin = CGPointMake(titleStatusLabelFrame.origin.x - titleIndicatorFrame.size.width - 4.0f, titleStatusLabelFrame.origin.y + indicatorOffset);
|
|
_titleStatusIndicator.frame = titleIndicatorFrame;
|
|
}
|
|
}
|
|
|
|
- (void)loadView
|
|
{
|
|
[super loadView];
|
|
|
|
[self setTitleText:TGLocalized(@"DialogList.Title")];
|
|
|
|
_titleContainer = [[TGDialogListTitleContainer alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 2.0f, 2.0f)];
|
|
[self setTitleView:_titleContainer];
|
|
|
|
_titleLabel = [[UILabel alloc] init];
|
|
_titleLabel.backgroundColor = [UIColor clearColor];
|
|
_titleLabel.textColor = [UIColor blackColor];
|
|
_titleLabel.font = TGBoldSystemFontOfSize(17.0f);
|
|
_titleLabel.text = TGLocalized(@"DialogList.Title");
|
|
[_titleLabel sizeToFit];
|
|
[_titleContainer addSubview:_titleLabel];
|
|
|
|
_titleLockIconView = [[TGLockIconView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 2.0f, 2.0f)];
|
|
_titleLockIconView.alpha = [TGDatabaseInstance() isPasswordSet:NULL] ? 1.0f : 0.0f;
|
|
[_titleLockIconView setIsLocked:[TGAppDelegateInstance isManuallyLocked] animated:false];
|
|
__weak TGDialogListController *weakSelf = self;
|
|
_titleContainer.tappped = ^
|
|
{
|
|
__strong TGDialogListController *strongSelf = weakSelf;
|
|
if (strongSelf != nil && strongSelf->_titleLockIconView.alpha > FLT_EPSILON)
|
|
{
|
|
[TGAppDelegateInstance setIsManuallyLocked:![TGAppDelegateInstance isManuallyLocked]];
|
|
[strongSelf->_titleLockIconView setIsLocked:[TGAppDelegateInstance isManuallyLocked] animated:true];
|
|
}
|
|
};
|
|
[_titleContainer addSubview:_titleLockIconView];
|
|
|
|
[self _layoutTitleViews:self.interfaceOrientation];
|
|
|
|
[self setLeftBarButtonItem:[self controllerLeftBarButtonItem]];
|
|
[self setRightBarButtonItem:[self controllerRightBarButtonItem]];
|
|
|
|
self.view.backgroundColor = [_dialogListCompanion.dialogListCellAssetsSource dialogListBackgroundColor];
|
|
|
|
_headerBackgroundView = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, self.view.frame.size.width, self.controllerInset.top)];
|
|
_headerBackgroundView.backgroundColor = [UIColor whiteColor];
|
|
[self.view addSubview:_headerBackgroundView];
|
|
|
|
CGRect tableFrame = self.view.bounds;
|
|
_tableView = [[TGListsTableView alloc] initWithFrame:tableFrame style:UITableViewStylePlain];
|
|
_tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
|
_tableView.delegate = self;
|
|
_tableView.dataSource = self;
|
|
_tableView.opaque = true;
|
|
_tableView.backgroundColor = nil;
|
|
|
|
//[self setExplicitTableInset:UIEdgeInsetsMake(-1.0f, 0.0f, 0.0f, 0.0f)];
|
|
|
|
[(TGListsTableView *)_tableView adjustBehaviour];
|
|
|
|
_tableView.showsVerticalScrollIndicator = true;
|
|
|
|
_searchBar = [[TGSearchBar alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, [TGSearchBar searchBarBaseHeight]) style:TGSearchBarStyleLightPlain];
|
|
_searchBar.autoresizingMask = UIViewAutoresizingFlexibleWidth;
|
|
|
|
_searchMixin = [[TGSearchDisplayMixin alloc] init];
|
|
_searchMixin.searchBar = _searchBar;
|
|
_searchMixin.delegate = self;
|
|
|
|
_tableView.tableHeaderView = _searchBar;
|
|
|
|
_searchBar.placeholder = TGLocalized(@"DialogList.SearchLabel");
|
|
|
|
_tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
|
|
_tableView.alwaysBounceVertical = true;
|
|
_tableView.bounces = true;
|
|
|
|
[self setTableHidden:_listModel.count == 0];
|
|
|
|
[self resetInitialOffset];
|
|
|
|
[self.view addSubview:_tableView];
|
|
|
|
if (![self _updateControllerInset:false])
|
|
[self controllerInsetUpdated:UIEdgeInsetsZero];
|
|
}
|
|
|
|
- (void)doUnloadView
|
|
{
|
|
_tableView.delegate = nil;
|
|
_tableView.dataSource = nil;
|
|
_tableView = nil;
|
|
|
|
_searchBar = nil;
|
|
|
|
_searchMixin.delegate = nil;
|
|
[_searchMixin unload];
|
|
}
|
|
|
|
- (void)viewDidUnload
|
|
{
|
|
[self doUnloadView];
|
|
|
|
[super viewDidUnload];
|
|
}
|
|
|
|
- (void)resetInitialOffset
|
|
{
|
|
if (!_doNotHideSearchAutomatically)
|
|
_tableView.contentOffset = CGPointMake(0.0f, -_tableView.contentInset.top + [TGSearchBar searchBarBaseHeight] + self.explicitTableInset.top);
|
|
}
|
|
|
|
- (void)viewWillAppear:(BOOL)animated
|
|
{
|
|
[super viewWillAppear:animated];
|
|
|
|
[self check3DTouch];
|
|
|
|
[self _layoutTitleViews:self.interfaceOrientation];
|
|
|
|
if ([_dialogListCompanion openedConversationId] == 0 || !TGIsPad())
|
|
{
|
|
if (lastAppearedConversationId != 0 && !_debugDoNotJump && !_dialogListCompanion.forwardMode && !_dialogListCompanion.privacyMode)
|
|
{
|
|
int64_t conversationId = lastAppearedConversationId;
|
|
lastAppearedConversationId = 0;
|
|
|
|
if (animated && !_searchMixin.isActive)
|
|
{
|
|
bool found = false;
|
|
|
|
int index = -1;
|
|
for (TGConversation *conversation in _listModel)
|
|
{
|
|
index++;
|
|
|
|
if (conversation.conversationId == conversationId)
|
|
{
|
|
UITableViewScrollPosition scrollPosition = UITableViewScrollPositionNone;
|
|
|
|
CGRect convertRect = [_tableView convertRect:[_tableView rectForRowAtIndexPath:[NSIndexPath indexPathForRow:index inSection:1]] toView:self.view];
|
|
if (convertRect.origin.y + convertRect.size.height > self.view.frame.size.height - self.controllerInset.bottom)
|
|
scrollPosition = UITableViewScrollPositionBottom;
|
|
else if (convertRect.origin.y < self.controllerInset.top)
|
|
scrollPosition = UITableViewScrollPositionTop;
|
|
|
|
if (_searchMixin.isActive)
|
|
scrollPosition = UITableViewScrollPositionNone;
|
|
|
|
[_tableView selectRowAtIndexPath:[NSIndexPath indexPathForRow:index inSection:1] animated:false scrollPosition:scrollPosition];
|
|
|
|
found = true;
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ([_tableView indexPathForSelectedRow] != nil)
|
|
[_tableView deselectRowAtIndexPath:[_tableView indexPathForSelectedRow] animated:animated];
|
|
}
|
|
}
|
|
|
|
if ([_tableView indexPathForSelectedRow] != nil)
|
|
[_tableView deselectRowAtIndexPath:[_tableView indexPathForSelectedRow] animated:animated];
|
|
}
|
|
|
|
if (_searchMixin.isActive)
|
|
{
|
|
[_searchMixin controllerLayoutUpdated:[TGViewController screenSizeForInterfaceOrientation:self.interfaceOrientation]];
|
|
|
|
UITableView *searchTableView = _searchMixin.searchResultsTableView;
|
|
|
|
if ([searchTableView indexPathForSelectedRow] != nil)
|
|
[searchTableView deselectRowAtIndexPath:[searchTableView indexPathForSelectedRow] animated:true];
|
|
}
|
|
}
|
|
|
|
- (void)viewDidAppear:(BOOL)animated
|
|
{
|
|
static dispatch_once_t onceToken;
|
|
dispatch_once(&onceToken, ^
|
|
{
|
|
TGLog(@"===== Dialog list did appear");
|
|
});
|
|
|
|
[_dialogListCompanion wakeUp];
|
|
|
|
for (id cell in _tableView.visibleCells)
|
|
{
|
|
if ([cell isKindOfClass:[TGDialogListCell class]])
|
|
{
|
|
[(TGDialogListCell *)cell restartAnimations:false];
|
|
}
|
|
}
|
|
|
|
_didSelectMessage = false;
|
|
|
|
if (_titleLockIconView.alpha > FLT_EPSILON && !_dialogListCompanion.forwardMode && !_dialogListCompanion.privacyMode)
|
|
{
|
|
|
|
#ifdef DEBUG
|
|
static bool staticVersion = false;
|
|
#else
|
|
static bool staticVersion = true;
|
|
#endif
|
|
|
|
NSString *key = @"Passcode_didShowChatListTooltip";
|
|
if (![[[NSUserDefaults standardUserDefaults] objectForKey:key] boolValue] || !staticVersion)
|
|
{
|
|
[[NSUserDefaults standardUserDefaults] setObject:@true forKey:key];
|
|
staticVersion = true;
|
|
|
|
if (_menuContainerView == nil)
|
|
{
|
|
_menuContainerView = [[TGMenuContainerView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, self.navigationController.view.frame.size.width, self.navigationController.view.frame.size.height)];
|
|
_menuContainerView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
|
[self.navigationController.view addSubview:_menuContainerView];
|
|
|
|
NSMutableArray *actions = [[NSMutableArray alloc] init];
|
|
[actions addObject:[[NSDictionary alloc] initWithObjectsAndKeys:TGLocalized(@"DialogList.PasscodeLockHelp"), @"title", nil]];
|
|
|
|
[_menuContainerView.menuView setButtonsAndActions:actions watcherHandle:nil];
|
|
[_menuContainerView.menuView sizeToFit];
|
|
_menuContainerView.menuView.userInteractionEnabled = false;
|
|
CGRect titleLockIconViewFrame = [_titleLockIconView convertRect:_titleLockIconView.bounds toView:_menuContainerView];
|
|
titleLockIconViewFrame.origin.y += 6.0f;
|
|
titleLockIconViewFrame.origin.x += 4.0f;
|
|
titleLockIconViewFrame.size.height += titleLockIconViewFrame.origin.y;
|
|
titleLockIconViewFrame.origin.y = 0;
|
|
[_menuContainerView showMenuFromRect:titleLockIconViewFrame animated:false];
|
|
}
|
|
}
|
|
}
|
|
|
|
[super viewDidAppear:animated];
|
|
}
|
|
|
|
- (void)viewWillDisappear:(BOOL)animated
|
|
{
|
|
if (iosMajorVersion() >= 7)
|
|
[_searchMixin resignResponderIfAny];
|
|
|
|
[super viewWillDisappear:animated];
|
|
}
|
|
|
|
- (void)viewDidDisappear:(BOOL)animated
|
|
{
|
|
if (animated)
|
|
{
|
|
for (NSIndexPath *indexPath in _tableView.indexPathsForVisibleRows)
|
|
{
|
|
UITableViewCell *cell = [_tableView cellForRowAtIndexPath:indexPath];
|
|
|
|
if ([cell isKindOfClass:[TGDialogListCell class]])
|
|
{
|
|
TGDialogListCell *dialogCell = (TGDialogListCell *)cell;
|
|
[dialogCell dismissEditingControls:false];
|
|
[dialogCell stopAnimations];
|
|
}
|
|
}
|
|
|
|
if (_searchMixin.isActive && !_didSelectMessage)
|
|
[_searchMixin setIsActive:false animated:false];
|
|
}
|
|
|
|
[super viewDidDisappear:animated];
|
|
}
|
|
|
|
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
|
|
{
|
|
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
|
|
}
|
|
|
|
- (BOOL)shouldAutorotate
|
|
{
|
|
return true;
|
|
}
|
|
|
|
- (void)controllerInsetUpdated:(UIEdgeInsets)previousInset
|
|
{
|
|
if (self.navigationBarShouldBeHidden)
|
|
{
|
|
[_tableView setContentOffset:CGPointMake(0, -_tableView.contentInset.top) animated:false];
|
|
}
|
|
|
|
if (_searchMixin != nil)
|
|
[_searchMixin controllerInsetUpdated:self.controllerInset];
|
|
|
|
_headerBackgroundView.frame = CGRectMake(0.0f, 0.0f, self.view.frame.size.width, self.controllerInset.top);
|
|
|
|
[super controllerInsetUpdated:previousInset];
|
|
}
|
|
|
|
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
|
|
{
|
|
[super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
|
|
}
|
|
|
|
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
|
|
{
|
|
[super willAnimateRotationToInterfaceOrientation:toInterfaceOrientation duration:duration];
|
|
|
|
[self _layoutTitleViews:toInterfaceOrientation];
|
|
|
|
if (_searchMixin != nil)
|
|
[_searchMixin controllerLayoutUpdated:[TGViewController screenSizeForInterfaceOrientation:toInterfaceOrientation]];
|
|
|
|
if (_emptyListContainer != nil)
|
|
{
|
|
_emptyListContainer.frame = CGRectMake(CGFloor((self.view.frame.size.width - 250) / 2), CGFloor((self.view.frame.size.height - _emptyListContainer.frame.size.height) / 2), _emptyListContainer.frame.size.width, _emptyListContainer.frame.size.height);
|
|
}
|
|
}
|
|
|
|
- (void)significantTimeChange:(NSNotification *)__unused notification
|
|
{
|
|
for (UITableViewCell *cell in _tableView.visibleCells)
|
|
{
|
|
if ([cell isKindOfClass:[TGDialogListCell class]])
|
|
{
|
|
TGDialogListCell *dialogCell = (TGDialogListCell *)cell;
|
|
[dialogCell resetView:true];
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void)didEnterBackground:(NSNotification *)__unused notification
|
|
{
|
|
for (UITableViewCell *cell in _tableView.visibleCells)
|
|
{
|
|
if ([cell isKindOfClass:[TGDialogListCell class]])
|
|
{
|
|
TGDialogListCell *dialogCell = (TGDialogListCell *)cell;
|
|
[dialogCell stopAnimations];
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void)willEnterForeground:(NSNotification *)__unused notification
|
|
{
|
|
for (UITableViewCell *cell in _tableView.visibleCells)
|
|
{
|
|
if ([cell isKindOfClass:[TGDialogListCell class]])
|
|
{
|
|
TGDialogListCell *dialogCell = (TGDialogListCell *)cell;
|
|
[dialogCell restartAnimations:true];
|
|
}
|
|
}
|
|
}
|
|
|
|
#pragma mark - List management
|
|
|
|
- (void)reloadData
|
|
{
|
|
NSMutableDictionary *temporaryImageCache = [[NSMutableDictionary alloc] init];
|
|
for (UITableViewCell *cell in _tableView.visibleCells)
|
|
{
|
|
if ([cell isKindOfClass:[TGDialogListCell class]])
|
|
{
|
|
[((TGDialogListCell *)cell) collectCachedPhotos:temporaryImageCache];
|
|
}
|
|
}
|
|
[[TGRemoteImageView sharedCache] addTemporaryCachedImagesSource:temporaryImageCache autoremove:true];
|
|
[_tableView reloadData];
|
|
}
|
|
|
|
- (void)resetState
|
|
{
|
|
[self setTableHidden:true];
|
|
[_emptyListContainer removeFromSuperview];
|
|
_emptyListContainer = nil;
|
|
}
|
|
|
|
- (void)dialogListFullyReloaded:(NSArray *)items
|
|
{
|
|
if (_listModel.count == 0)
|
|
[self resetInitialOffset];
|
|
|
|
_isLoading = false;
|
|
|
|
int64_t selectedConversation = INT64_MAX;
|
|
NSIndexPath *selectedIndexPath = [_tableView indexPathForSelectedRow];
|
|
if (selectedIndexPath != nil)
|
|
{
|
|
if (selectedIndexPath.row < (NSInteger)_listModel.count)
|
|
{
|
|
TGConversation *conversation = [_listModel objectAtIndex:selectedIndexPath.row];
|
|
selectedConversation = conversation.conversationId;
|
|
}
|
|
}
|
|
|
|
[_listModel removeAllObjects];
|
|
[_listModel addObjectsFromArray:items];
|
|
|
|
[self reloadData];
|
|
|
|
if (selectedConversation != INT64_MAX)
|
|
{
|
|
int index = -1;
|
|
for (TGConversation *conversation in _listModel)
|
|
{
|
|
index++;
|
|
int64_t conversationId = conversation.conversationId;
|
|
if (conversationId == selectedConversation)
|
|
{
|
|
[_tableView selectRowAtIndexPath:[NSIndexPath indexPathForRow:index inSection:1] animated:false scrollPosition:UITableViewScrollPositionNone];
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static dispatch_once_t onceToken;
|
|
dispatch_once(&onceToken, ^
|
|
{
|
|
TGLog(@"===== Dialog list reloaded");
|
|
});
|
|
|
|
[self updateEmptyListContainer];
|
|
}
|
|
|
|
- (void)updateEmptyListContainer
|
|
{
|
|
if (_listModel.count == 0 && _emptyListContainer == nil)
|
|
{
|
|
_emptyListContainer = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 250, 0)];
|
|
[self.view insertSubview:_emptyListContainer belowSubview:_tableView];
|
|
|
|
UILabel *titleLabel = [[UILabel alloc] init];
|
|
titleLabel.backgroundColor = [UIColor clearColor];
|
|
titleLabel.textColor = UIColorRGB(0x999999);
|
|
titleLabel.font = TGSystemFontOfSize(20);
|
|
titleLabel.text = TGLocalized(@"DialogList.NoMessagesTitle");
|
|
[titleLabel sizeToFit];
|
|
titleLabel.frame = CGRectOffset(titleLabel.frame, CGFloor((_emptyListContainer.frame.size.width - titleLabel.frame.size.width) / 2), 0.0f);
|
|
[_emptyListContainer addSubview:titleLabel];
|
|
|
|
UILabel *textLabel = [[UILabel alloc] init];
|
|
textLabel.textAlignment = NSTextAlignmentCenter;
|
|
textLabel.lineBreakMode = NSLineBreakByWordWrapping;
|
|
textLabel.numberOfLines = 0;
|
|
textLabel.backgroundColor = [UIColor clearColor];
|
|
textLabel.textColor = UIColorRGB(0x999999);
|
|
textLabel.font = TGSystemFontOfSize(15);
|
|
textLabel.text = TGLocalized(@"DialogList.NoMessagesText");
|
|
CGSize textLabelSize = [textLabel sizeThatFits:CGSizeMake(300, 1000)];
|
|
textLabel.frame = CGRectMake(CGFloor((_emptyListContainer.frame.size.width - textLabelSize.width) / 2), titleLabel.frame.origin.y + titleLabel.frame.size.height + 14, textLabelSize.width, textLabelSize.height);
|
|
[_emptyListContainer addSubview:textLabel];
|
|
|
|
CGFloat containerHeight = textLabel.frame.origin.y + textLabel.frame.size.height;
|
|
|
|
_emptyListContainer.frame = CGRectMake(CGFloor((self.view.frame.size.width - 250) / 2), CGFloor((self.view.frame.size.height - containerHeight) / 2), _emptyListContainer.frame.size.width, containerHeight);
|
|
}
|
|
else if (_emptyListContainer != nil && _listModel.count != 0)
|
|
{
|
|
[_emptyListContainer removeFromSuperview];
|
|
_emptyListContainer = nil;
|
|
}
|
|
|
|
[self setTableHidden:_listModel.count == 0];
|
|
|
|
if (_emptyListContainer != nil)
|
|
_emptyListContainer.hidden = ![_dialogListCompanion shouldDisplayEmptyListPlaceholder];
|
|
}
|
|
|
|
- (void)setTableHidden:(bool)tableHidden
|
|
{
|
|
_tableView.hidden = tableHidden;
|
|
self.view.backgroundColor = tableHidden ? [UIColor whiteColor] : [_dialogListCompanion.dialogListCellAssetsSource dialogListBackgroundColor];
|
|
}
|
|
|
|
- (void)dialogListItemsChanged:(NSArray *)__unused insertedIndices insertedItems:(NSArray *)__unused insertedItems updatedIndices:(NSArray *)__unused updatedIndices updatedItems:(NSArray *)__unused updatedItems removedIndices:(NSArray *)__unused removedIndices
|
|
{
|
|
int countBefore = (int)_listModel.count;
|
|
|
|
NSMutableArray *removedIndexPaths = [[NSMutableArray alloc] init];
|
|
for (NSNumber *nRemovedIndex in removedIndices)
|
|
{
|
|
[_listModel removeObjectAtIndex:[nRemovedIndex intValue]];
|
|
[removedIndexPaths addObject:[NSIndexPath indexPathForRow:[nRemovedIndex intValue] inSection:1]];
|
|
}
|
|
|
|
if (removedIndexPaths.count != 0)
|
|
{
|
|
[_tableView beginUpdates];
|
|
[_tableView deleteRowsAtIndexPaths:removedIndexPaths withRowAnimation:UITableViewRowAnimationRight];
|
|
[_tableView endUpdates];
|
|
}
|
|
|
|
int index = -1;
|
|
for (NSNumber *nUpdatedIndex in updatedIndices)
|
|
{
|
|
index++;
|
|
[_listModel replaceObjectAtIndex:[nUpdatedIndex intValue] withObject:[updatedItems objectAtIndex:index]];
|
|
}
|
|
|
|
for (NSNumber *nUpdatedIndex in updatedIndices)
|
|
{
|
|
TGDialogListCell *cell = (TGDialogListCell *)[_tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:[nUpdatedIndex intValue] inSection:1]];
|
|
if (cell != nil)
|
|
{
|
|
TGConversation *conversation = [_listModel objectAtIndex:[nUpdatedIndex intValue]];
|
|
|
|
[self prepareCell:cell forConversation:conversation animated:true isSearch:false];
|
|
}
|
|
}
|
|
|
|
if ((countBefore == 0) != (_listModel.count == 0))
|
|
{
|
|
[self updateEmptyListContainer];
|
|
|
|
if (_listModel.count == 0)
|
|
[self setupEditingMode:false setupTable:true];
|
|
}
|
|
}
|
|
|
|
- (void)selectConversationWithId:(int64_t)conversationId
|
|
{
|
|
bool found = false;
|
|
|
|
int index = -1;
|
|
for (TGConversation *conversation in _listModel)
|
|
{
|
|
index++;
|
|
|
|
if (conversation.conversationId == conversationId)
|
|
{
|
|
UITableViewScrollPosition scrollPosition = UITableViewScrollPositionNone;
|
|
|
|
CGRect convertRect = [_tableView convertRect:[_tableView rectForRowAtIndexPath:[NSIndexPath indexPathForRow:index inSection:1]] toView:self.view];
|
|
if (convertRect.origin.y + convertRect.size.height > self.view.frame.size.height - self.controllerInset.bottom)
|
|
scrollPosition = UITableViewScrollPositionBottom;
|
|
else if (convertRect.origin.y < self.controllerInset.top)
|
|
scrollPosition = UITableViewScrollPositionTop;
|
|
|
|
if (_searchMixin.isActive)
|
|
scrollPosition = UITableViewScrollPositionNone;
|
|
|
|
[_tableView selectRowAtIndexPath:[NSIndexPath indexPathForRow:index inSection:1] animated:false scrollPosition:scrollPosition];
|
|
|
|
found = true;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!found && [_tableView indexPathForSelectedRow] != nil)
|
|
[_tableView deselectRowAtIndexPath:[_tableView indexPathForSelectedRow] animated:false];
|
|
}
|
|
|
|
- (void)searchResultsReloaded:(NSDictionary *)items searchString:(NSString *)searchString
|
|
{
|
|
NSMutableArray *searchResultsSections = [[NSMutableArray alloc] init];
|
|
|
|
if ([(NSArray *)items[@"hashtags"] count] != 0)
|
|
{
|
|
[searchResultsSections addObject:@{@"items": items[@"hashtags"], @"type": @"hashtags"}];
|
|
}
|
|
|
|
if ([(NSArray *)items[@"dialogs"] count] != 0)
|
|
{
|
|
[searchResultsSections addObject:@{@"title": TGLocalized(@"DialogList.SearchSectionDialogs"), @"items": items[@"dialogs"], @"type": @"dialogs"}];
|
|
}
|
|
|
|
if ([(NSArray *)items[@"global"] count] != 0)
|
|
{
|
|
[searchResultsSections addObject:@{@"title": TGLocalized(@"DialogList.SearchSectionGlobal"), @"items": items[@"global"], @"type": @"global"}];
|
|
}
|
|
|
|
if ([(NSArray *)items[@"messages"] count] != 0)
|
|
{
|
|
[searchResultsSections addObject:@{@"title": TGLocalized(@"DialogList.SearchSectionMessages"), @"items": items[@"messages"], @"type": @"messages"}];
|
|
}
|
|
|
|
_searchResultsSections = searchResultsSections;
|
|
_searchResultsQuery = searchString;
|
|
|
|
[_searchMixin reloadSearchResults];
|
|
|
|
[_searchMixin setSearchResultsTableViewHidden:searchString.length == 0];
|
|
}
|
|
|
|
#pragma mark - Interface logic
|
|
|
|
- (void)editButtonPressed
|
|
{
|
|
[self setupEditingMode:!_editingMode];
|
|
|
|
[self setLeftBarButtonItem:[self controllerLeftBarButtonItem] animated:true];
|
|
[self setRightBarButtonItem:[self controllerRightBarButtonItem] animated:true];
|
|
}
|
|
|
|
- (void)doneButtonPressed
|
|
{
|
|
[self setupEditingMode:!_editingMode];
|
|
|
|
[self setLeftBarButtonItem:[self controllerLeftBarButtonItem] animated:true];
|
|
[self setRightBarButtonItem:[self controllerRightBarButtonItem] animated:true];
|
|
|
|
for (UITableViewCell *cell in _tableView.visibleCells)
|
|
{
|
|
if ([cell isKindOfClass:[TGDialogListCell class]])
|
|
{
|
|
[(TGDialogListCell *)cell dismissEditingControls:true];
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void)setupEditingMode:(bool)editing
|
|
{
|
|
[self setupEditingMode:editing setupTable:true];
|
|
}
|
|
|
|
- (void)setupEditingMode:(bool)editing setupTable:(bool)setupTable
|
|
{
|
|
_editingMode = editing;
|
|
if (setupTable)
|
|
[_tableView setEditing:editing animated:true];
|
|
|
|
if (!editing)
|
|
[self selectCurrentConversation];
|
|
}
|
|
|
|
- (void)dismissEditingControls
|
|
{
|
|
if (_editingMode && !_tableView.editing)
|
|
[self setupEditingMode:false setupTable:false];
|
|
}
|
|
|
|
- (void)composeMessageButtonPressed:(id)__unused sender
|
|
{
|
|
[_dialogListCompanion composeMessage];
|
|
}
|
|
|
|
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
|
|
{
|
|
static bool canSelect = true;
|
|
if (canSelect)
|
|
{
|
|
canSelect = false;
|
|
dispatch_async(dispatch_get_main_queue(), ^
|
|
{
|
|
canSelect = true;
|
|
});
|
|
}
|
|
else
|
|
return;
|
|
|
|
if (TGIsPad())
|
|
[self.view endEditing:true];
|
|
|
|
if (tableView == _tableView)
|
|
{
|
|
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
|
|
if (cell.selectionStyle != UITableViewCellSelectionStyleNone)
|
|
{
|
|
TGConversation *conversation = nil;
|
|
if (indexPath.row < (NSInteger)_listModel.count)
|
|
conversation = [_listModel objectAtIndex:indexPath.row];
|
|
|
|
if (conversation != nil)
|
|
{
|
|
[_dialogListCompanion conversationSelected:conversation];
|
|
}
|
|
|
|
if (_dialogListCompanion.forwardMode || _dialogListCompanion.privacyMode)
|
|
[_tableView deselectRowAtIndexPath:indexPath animated:true];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
id result = [_searchResultsSections[indexPath.section][@"items"] objectAtIndex:indexPath.row];
|
|
|
|
if ([result isKindOfClass:[TGConversation class]])
|
|
{
|
|
[_searchDisposable setDisposable:nil];
|
|
TGConversation *conversation = (TGConversation *)result;
|
|
if ([conversation.additionalProperties objectForKey:@"searchMessageId"] != nil)
|
|
{
|
|
_didSelectMessage = true;
|
|
[_dialogListCompanion searchResultSelectedConversation:(TGConversation *)result atMessageId:[[conversation.additionalProperties objectForKey:@"searchMessageId"] intValue]];
|
|
}
|
|
else
|
|
{
|
|
[_searchDisposable setDisposable:nil];
|
|
[TGGlobalMessageSearchSignals addRecentPeerResult:((TGConversation *)result).conversationId];
|
|
[_dialogListCompanion searchResultSelectedConversation:(TGConversation *)result];
|
|
}
|
|
}
|
|
else if ([result isKindOfClass:[TGUser class]])
|
|
{
|
|
[_searchDisposable setDisposable:nil];
|
|
[_dialogListCompanion searchResultSelectedUser:(TGUser *)result];
|
|
[TGGlobalMessageSearchSignals addRecentPeerResult:((TGUser *)result).uid];
|
|
}
|
|
else if ([result isKindOfClass:[TGMessage class]])
|
|
{
|
|
_didSelectMessage = true;
|
|
[_dialogListCompanion searchResultSelectedMessage:(TGMessage *)result];
|
|
}
|
|
else
|
|
{
|
|
[_searchBar setText:[@"#" stringByAppendingString:result]];
|
|
}
|
|
}
|
|
|
|
if (_dialogListCompanion.forwardMode)
|
|
[tableView deselectRowAtIndexPath:indexPath animated:true];
|
|
}
|
|
|
|
#pragma mark - Table logic
|
|
|
|
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
|
|
{
|
|
if (tableView == _tableView)
|
|
return 2;
|
|
|
|
return _searchResultsSections.count;
|
|
}
|
|
|
|
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
|
|
{
|
|
if (tableView == _tableView)
|
|
{
|
|
if (section == 0)
|
|
return (TGIsPad() && _dialogListCompanion.showBroadcastsMenu) ? 1 : 0;
|
|
|
|
return _listModel.count;
|
|
}
|
|
else
|
|
return [(NSArray *)_searchResultsSections[section][@"items"] count];
|
|
}
|
|
|
|
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
|
|
{
|
|
if (tableView == _tableView)
|
|
{
|
|
if (indexPath.section == 0)
|
|
return 45.0f;
|
|
|
|
int row = (int)indexPath.row;
|
|
if (row >= 0 && row < (NSInteger)_listModel.count)
|
|
return 76;
|
|
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
if ([_searchResultsSections[indexPath.section][@"type"] isEqualToString:@"messages"])
|
|
return 76.0f;
|
|
else if ([_searchResultsSections[indexPath.section][@"type"] isEqualToString:@"hashtags"])
|
|
return 43.0f;
|
|
return 51.0f;
|
|
}
|
|
}
|
|
|
|
- (void)prepareCell:(TGDialogListCell *)cell forConversation:(TGConversation *)conversation animated:(bool)animated isSearch:(bool)isSearch
|
|
{
|
|
if (cell.reuseTag != (intptr_t)conversation || cell.conversationId != conversation.conversationId || cell.unreadCount != conversation.unreadCount)
|
|
{
|
|
cell.reuseTag = (intptr_t)conversation;
|
|
cell.conversationId = conversation.conversationId;
|
|
|
|
cell.date = conversation.date;
|
|
|
|
if (conversation.deliveryError)
|
|
cell.deliveryState = TGMessageDeliveryStateFailed;
|
|
else
|
|
cell.deliveryState = conversation.deliveryState;
|
|
|
|
NSDictionary *dialogListData = conversation.dialogListData;
|
|
|
|
cell.titleText = [dialogListData objectForKey:@"title"];
|
|
cell.titleLetters = [dialogListData objectForKey:@"titleLetters"];
|
|
|
|
cell.isBroadcast = [dialogListData[@"isBroadcast"] boolValue];
|
|
|
|
cell.isChannel = TGPeerIdIsChannel(conversation.conversationId);
|
|
cell.isVerified = [dialogListData[@"isVerified"] boolValue];
|
|
|
|
cell.isEncrypted = [dialogListData[@"isEncrypted"] boolValue];
|
|
cell.encryptionStatus = [dialogListData[@"encryptionStatus"] intValue];
|
|
cell.encryptedUserId = [dialogListData[@"encryptedUserId"] intValue];
|
|
cell.encryptionOutgoing = [dialogListData[@"encryptionOutgoing"] boolValue];
|
|
cell.encryptionFirstName = dialogListData[@"encryptionFirstName"];
|
|
|
|
NSNumber *nIsChat = [dialogListData objectForKey:@"isChat"];
|
|
if (nIsChat != nil && [nIsChat boolValue])
|
|
{
|
|
NSArray *chatAvatarUrls = [dialogListData objectForKey:@"chatAvatarUrls"];
|
|
cell.groupChatAvatarCount = (int)chatAvatarUrls.count;
|
|
cell.groupChatAvatarUrls = chatAvatarUrls;
|
|
cell.isGroupChat = true;
|
|
cell.avatarUrl = [dialogListData objectForKey:@"avatarUrl"];
|
|
|
|
NSString *authorName = [dialogListData objectForKey:@"authorName"];
|
|
cell.authorName = [authorName isEqualToString:authorNameYou] ? TGLocalized(@"DialogList.You") : authorName;
|
|
}
|
|
else
|
|
{
|
|
cell.avatarUrl = [dialogListData objectForKey:@"avatarUrl"];
|
|
cell.isGroupChat = false;
|
|
|
|
NSString *authorName = [dialogListData objectForKey:@"authorName"];
|
|
cell.authorName = [authorName isEqualToString:authorNameYou] ? TGLocalized(@"DialogList.You") : authorName;
|
|
}
|
|
|
|
cell.isMuted = [[dialogListData objectForKey:@"mute"] boolValue];
|
|
|
|
cell.unread = conversation.unread;
|
|
if (!isSearch)
|
|
{
|
|
if ([_dialogListCompanion isConversationOpened:conversation.conversationId])
|
|
{
|
|
cell.unreadCount = 0;
|
|
cell.serviceUnreadCount = 0;
|
|
}
|
|
else
|
|
{
|
|
cell.unreadCount = conversation.unreadCount;
|
|
cell.serviceUnreadCount = conversation.serviceUnreadCount;
|
|
}
|
|
}
|
|
cell.outgoing = conversation.outgoing;
|
|
|
|
cell.messageText = conversation.text;
|
|
cell.messageAttachments = conversation.media;
|
|
cell.users = [dialogListData objectForKey:@"users"];
|
|
|
|
[cell resetView:animated];
|
|
}
|
|
|
|
if (!isSearch)
|
|
{
|
|
std::map<int64_t, NSString *>::iterator typingIt = _usersTypingInConversation.find(conversation.conversationId);
|
|
if (typingIt == _usersTypingInConversation.end())
|
|
[cell setTypingString:nil];
|
|
else
|
|
[cell setTypingString:typingIt->second];
|
|
}
|
|
|
|
[cell restartAnimations:false];
|
|
}
|
|
|
|
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
|
|
{
|
|
TGUser *user = nil;
|
|
TGConversation *conversation = nil;
|
|
TGMessage *message = nil;
|
|
NSString *hashtag = nil;
|
|
bool isGlobalSearch = false;
|
|
bool isMessageSearch = false;
|
|
|
|
if (tableView == _tableView)
|
|
{
|
|
if (indexPath.section == 0)
|
|
{
|
|
static NSString *TGDialogListBroadcastsMenuCellIdentifier = @"TGDialogListBroadcastsMenuCell";
|
|
TGDialogListBroadcastsMenuCell *cell = (TGDialogListBroadcastsMenuCell *)[tableView dequeueReusableCellWithIdentifier:TGDialogListBroadcastsMenuCellIdentifier];
|
|
if (cell == nil)
|
|
{
|
|
cell = [[TGDialogListBroadcastsMenuCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:TGDialogListBroadcastsMenuCellIdentifier];
|
|
|
|
__weak TGDialogListController *weakSelf = self;
|
|
cell.broadcastListsPressed = ^
|
|
{
|
|
__strong TGDialogListController *strongSelf = weakSelf;
|
|
[strongSelf.dialogListCompanion navigateToBroadcastLists];
|
|
};
|
|
|
|
cell.newGroupPressed = ^
|
|
{
|
|
__strong TGDialogListController *strongSelf = weakSelf;
|
|
[strongSelf.dialogListCompanion navigateToNewGroup];
|
|
};
|
|
}
|
|
|
|
return cell;
|
|
}
|
|
else
|
|
{
|
|
if (indexPath.row < (NSInteger)_listModel.count)
|
|
conversation = [_listModel objectAtIndex:indexPath.row];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
id result = [_searchResultsSections[indexPath.section][@"items"] objectAtIndex:indexPath.row];
|
|
if ([result isKindOfClass:[TGConversation class]])
|
|
{
|
|
conversation = result;
|
|
isMessageSearch = [_searchResultsSections[indexPath.section][@"type"] isEqualToString:@"messages"];
|
|
isGlobalSearch = [_searchResultsSections[indexPath.section][@"type"] isEqualToString:@"global"];
|
|
}
|
|
else if ([result isKindOfClass:[TGUser class]])
|
|
{
|
|
user = result;
|
|
isGlobalSearch = [_searchResultsSections[indexPath.section][@"type"] isEqualToString:@"global"];
|
|
}
|
|
else if ([result isKindOfClass:[TGMessage class]])
|
|
message = result;
|
|
else
|
|
hashtag = result;
|
|
}
|
|
|
|
if (tableView == _tableView)
|
|
{
|
|
if (conversation != nil)
|
|
{
|
|
static NSString *MessageCellIdentifier = @"MC";
|
|
TGDialogListCell *cell = [tableView dequeueReusableCellWithIdentifier:MessageCellIdentifier];
|
|
|
|
if (cell == nil)
|
|
{
|
|
if (cell == nil)
|
|
{
|
|
cell = [[TGDialogListCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:MessageCellIdentifier assetsSource:[_dialogListCompanion dialogListCellAssetsSource]];
|
|
cell.watcherHandle = _actionHandle;
|
|
cell.enableEditing = ![_dialogListCompanion forwardMode] && !_dialogListCompanion.privacyMode;
|
|
}
|
|
}
|
|
|
|
[self prepareCell:cell forConversation:conversation animated:false isSearch:false];
|
|
|
|
return cell;
|
|
}
|
|
|
|
static NSString *PlaceholderCellIdentifier = @"LC";
|
|
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:PlaceholderCellIdentifier];
|
|
if (cell == nil)
|
|
{
|
|
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:PlaceholderCellIdentifier];
|
|
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
|
|
cell.contentView.backgroundColor = [UIColor clearColor];
|
|
|
|
UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
|
|
spinner.tag = 10000;
|
|
spinner.frame = CGRectMake(0, 0, 24, 24);
|
|
spinner.center = cell.center;
|
|
spinner.autoresizingMask = (UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin);
|
|
[cell.contentView addSubview:spinner];
|
|
}
|
|
UIActivityIndicatorView *spinner = (UIActivityIndicatorView *)[cell viewWithTag:10000];
|
|
if (_canLoadMore)
|
|
{
|
|
spinner.hidden = false;
|
|
[spinner startAnimating];
|
|
}
|
|
else
|
|
{
|
|
spinner.hidden = true;
|
|
[spinner stopAnimating];
|
|
}
|
|
return cell;
|
|
}
|
|
else
|
|
{
|
|
if ((conversation != nil || user != nil) && !isMessageSearch)
|
|
{
|
|
static NSString *SearchCellIdentifier = @"UC";
|
|
TGDialogListSearchCell *cell = [tableView dequeueReusableCellWithIdentifier:SearchCellIdentifier];
|
|
if (cell == nil)
|
|
{
|
|
cell = [[TGDialogListSearchCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:SearchCellIdentifier assetsSource:[_dialogListCompanion dialogListCellAssetsSource]];
|
|
}
|
|
|
|
cell.isEncrypted = false;
|
|
cell.encryptedUserId = 0;
|
|
cell.isVerified = false;
|
|
|
|
if (conversation != nil)
|
|
{
|
|
NSDictionary *dialogListData = conversation.dialogListData;
|
|
|
|
cell.isEncrypted = [dialogListData[@"isEncrypted"] boolValue];
|
|
|
|
if (cell.isEncrypted)
|
|
{
|
|
cell.titleTextFirst = dialogListData[@"firstName"];
|
|
cell.titleTextSecond = dialogListData[@"lastName"];
|
|
}
|
|
else
|
|
{
|
|
cell.titleTextFirst = [dialogListData objectForKey:@"title"];
|
|
cell.titleTextSecond = nil;
|
|
}
|
|
|
|
cell.isVerified = conversation.isVerified;
|
|
|
|
NSNumber *nIsChat = [dialogListData objectForKey:@"isChat"];
|
|
if (nIsChat != nil && [nIsChat boolValue])
|
|
cell.isChat = true;
|
|
|
|
cell.avatarUrl = [dialogListData objectForKey:@"avatarUrl"];
|
|
|
|
if (isGlobalSearch && conversation.username.length != 0){
|
|
NSString *string = [[NSString alloc] initWithFormat:@"@%@", conversation.username];
|
|
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:string attributes:@{NSFontAttributeName: TGSystemFontOfSize(14.0f)}];
|
|
[attributedString addAttribute:NSForegroundColorAttributeName value:UIColorRGB(0x888888) range:NSMakeRange(0, string.length)];
|
|
if (_searchResultsQuery.length != 0)
|
|
{
|
|
NSRange range = [[string lowercaseString] rangeOfString:[_searchResultsQuery lowercaseString]];
|
|
if (range.location != NSNotFound)
|
|
{
|
|
if (range.location == 1)
|
|
{
|
|
range.location = 0;
|
|
range.length++;
|
|
}
|
|
[attributedString addAttribute:NSForegroundColorAttributeName value:TGAccentColor() range:range];
|
|
}
|
|
}
|
|
cell.attributedSubtitleText = attributedString;
|
|
} else {
|
|
cell.attributedSubtitleText = nil;
|
|
}
|
|
|
|
cell.conversationId = conversation.conversationId;
|
|
cell.encryptedUserId = [dialogListData[@"encryptedUserId"] intValue];
|
|
|
|
cell.unreadCount = conversation.unreadCount;
|
|
}
|
|
else if (user != nil)
|
|
{
|
|
cell.isChat = false;
|
|
|
|
cell.avatarUrl = user.photoUrlSmall;
|
|
if (user.firstName.length == 0)
|
|
{
|
|
cell.titleTextFirst = user.lastName;
|
|
cell.titleTextSecond = nil;
|
|
}
|
|
else
|
|
{
|
|
cell.titleTextFirst = user.firstName;
|
|
cell.titleTextSecond = user.lastName;
|
|
}
|
|
|
|
if (isGlobalSearch)
|
|
{
|
|
NSString *string = [[NSString alloc] initWithFormat:@"@%@", user.userName];
|
|
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:string attributes:@{NSFontAttributeName: TGSystemFontOfSize(14.0f)}];
|
|
[attributedString addAttribute:NSForegroundColorAttributeName value:UIColorRGB(0x888888) range:NSMakeRange(0, string.length)];
|
|
if (_searchResultsQuery.length != 0)
|
|
{
|
|
NSRange range = [[string lowercaseString] rangeOfString:[_searchResultsQuery lowercaseString]];
|
|
if (range.location != NSNotFound)
|
|
{
|
|
if (range.location == 1)
|
|
{
|
|
range.location = 0;
|
|
range.length++;
|
|
}
|
|
[attributedString addAttribute:NSForegroundColorAttributeName value:TGAccentColor() range:range];
|
|
}
|
|
}
|
|
cell.attributedSubtitleText = attributedString;
|
|
}
|
|
else
|
|
cell.attributedSubtitleText = nil;
|
|
|
|
cell.unreadCount = conversation.unreadCount;
|
|
|
|
cell.conversationId = user.uid;
|
|
}
|
|
|
|
[cell resetView:false];
|
|
return cell;
|
|
}
|
|
else if (conversation != nil)
|
|
{
|
|
static NSString *MessageCellIdentifier = @"MC";
|
|
TGDialogListCell *cell = [tableView dequeueReusableCellWithIdentifier:MessageCellIdentifier];
|
|
|
|
if (cell == nil)
|
|
{
|
|
if (cell == nil)
|
|
{
|
|
cell = [[TGDialogListCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:MessageCellIdentifier assetsSource:[_dialogListCompanion dialogListCellAssetsSource]];
|
|
cell.watcherHandle = _actionHandle;
|
|
cell.enableEditing = false;
|
|
}
|
|
}
|
|
|
|
[self prepareCell:cell forConversation:conversation animated:false isSearch:true];
|
|
|
|
return cell;
|
|
}
|
|
else if (hashtag != nil)
|
|
{
|
|
TGHashtagPanelCell *cell = [tableView dequeueReusableCellWithIdentifier:TGHashtagPanelCellKind];
|
|
|
|
if (cell == nil)
|
|
{
|
|
cell = [[TGHashtagPanelCell alloc] initWithStyle:TGModernConversationAssociatedInputPanelDefaultStyle];
|
|
[cell setDisplaySeparator:true];
|
|
}
|
|
|
|
[cell setHashtag:hashtag];
|
|
|
|
return cell;
|
|
}
|
|
}
|
|
|
|
return nil;
|
|
}
|
|
|
|
#pragma mark -
|
|
|
|
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)__unused cell forRowAtIndexPath:(NSIndexPath *)indexPath
|
|
{
|
|
if (tableView == _tableView)
|
|
{
|
|
int listCount = (int)_listModel.count;
|
|
if (_canLoadMore && !_isLoading && listCount != 0 && (listCount < 10 || indexPath.row >= listCount - 10))
|
|
{
|
|
_isLoading = true;
|
|
[_dialogListCompanion loadMoreItems];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
}
|
|
}
|
|
|
|
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
|
|
{
|
|
if (tableView == _tableView)
|
|
{
|
|
if (indexPath.section == 0)
|
|
return false;
|
|
|
|
TGConversation *conversation = _listModel[indexPath.row];
|
|
if ([conversation isKindOfClass:[TGConversation class]] && conversation.isChannel && conversation.channelRole == TGChannelRoleCreator) {
|
|
return false;
|
|
}
|
|
|
|
return indexPath.row < (NSInteger)_listModel.count;
|
|
}
|
|
else
|
|
{
|
|
if ([_searchResultsSections[indexPath.section][@"type"] isEqualToString:@"recent"])
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
- (UITableViewCellEditingStyle)tableView:(UITableView *)__unused tableView editingStyleForRowAtIndexPath:(NSIndexPath *)__unused indexPath
|
|
{
|
|
return UITableViewCellEditingStyleDelete;
|
|
}
|
|
|
|
- (BOOL)tableView:(UITableView *)tableView shouldIndentWhileEditingRowAtIndexPath:(NSIndexPath *)indexPath
|
|
{
|
|
if (tableView == _tableView)
|
|
return indexPath.row < (NSInteger)_listModel.count;
|
|
return true;
|
|
}
|
|
|
|
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
|
|
{
|
|
_currentActionSheet.delegate = nil;
|
|
_currentActionSheet = nil;
|
|
|
|
if (buttonIndex != actionSheet.cancelButtonIndex)
|
|
{
|
|
if (buttonIndex == actionSheet.destructiveButtonIndex)
|
|
{
|
|
if (_conversationIdToDelete != 0)
|
|
{
|
|
for (TGConversation *conversation in _listModel)
|
|
{
|
|
if (conversation.conversationId == _conversationIdToDelete)
|
|
{
|
|
[_dialogListCompanion deleteItem:conversation animated:true];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (_conversationIdToDelete != 0)
|
|
{
|
|
for (TGConversation *conversation in _listModel)
|
|
{
|
|
if (conversation.conversationId == _conversationIdToDelete)
|
|
{
|
|
[_dialogListCompanion clearItem:conversation animated:true];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
_conversationIdToDelete = 0;
|
|
}
|
|
|
|
#pragma mark -
|
|
|
|
- (UITableView *)createTableViewForSearchMixin:(TGSearchDisplayMixin *)__unused searchMixin
|
|
{
|
|
UITableView *tableView = [[UITableView alloc] init];
|
|
|
|
tableView.delegate = self;
|
|
tableView.dataSource = self;
|
|
|
|
tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
|
|
if (tableView.tableFooterView == nil)
|
|
tableView.tableFooterView = [[UIView alloc] init];
|
|
|
|
return tableView;
|
|
}
|
|
|
|
- (UIView *)referenceViewForSearchResults
|
|
{
|
|
return _tableView;
|
|
}
|
|
|
|
- (void)searchMixin:(TGSearchDisplayMixin *)__unused searchMixin hasChangedSearchQuery:(NSString *)searchQuery withScope:(int)__unused scope
|
|
{
|
|
if (searchQuery.length == 0)
|
|
{
|
|
[_searchDisposable setDisposable:nil];
|
|
_searchResultsSections = _recentSearchResultsSections;
|
|
[_searchMixin reloadSearchResults];
|
|
[_searchMixin setSearchResultsTableViewHidden:false];
|
|
}
|
|
else
|
|
{
|
|
if (_searchDisposable == nil)
|
|
_searchDisposable = [[SMetaDisposable alloc] init];
|
|
__weak TGDialogListController *weakSelf = self;
|
|
_searchBar.delayActivity = false;
|
|
_searchBar.showActivity = true;
|
|
[_searchDisposable setDisposable:[[[TGGlobalMessageSearchSignals search:searchQuery includeMessages:!_dialogListCompanion.forwardMode itemMapping:^id(id item)
|
|
{
|
|
__strong TGDialogListController *strongSelf = weakSelf;
|
|
if (strongSelf != nil)
|
|
return [strongSelf.dialogListCompanion processSearchResultItem:item];
|
|
return nil;
|
|
}] onDispose:^
|
|
{
|
|
TGDispatchOnMainThread(^
|
|
{
|
|
_searchBar.showActivity = false;
|
|
});
|
|
}] startWithNext:^(NSDictionary *result)
|
|
{
|
|
TGDispatchOnMainThread(^
|
|
{
|
|
if ([searchQuery isEqualToString:_searchBar.text])
|
|
{
|
|
__strong TGDialogListController *strongSelf = weakSelf;
|
|
[strongSelf searchResultsReloaded:result searchString:searchQuery];
|
|
}
|
|
});
|
|
} error:^(__unused id error)
|
|
{
|
|
TGDispatchOnMainThread(^
|
|
{
|
|
_searchBar.showActivity = false;
|
|
});
|
|
} completed:^
|
|
{
|
|
TGDispatchOnMainThread(^
|
|
{
|
|
_searchBar.showActivity = false;
|
|
});
|
|
}]];
|
|
}
|
|
}
|
|
|
|
- (void)searchMixinWillActivate:(bool)animated
|
|
{
|
|
_isDisplayingSearch = true;
|
|
_tableView.scrollEnabled = false;
|
|
|
|
[self setNavigationBarHidden:true animated:animated];
|
|
|
|
if (_recentSearchResultsDisposable == nil)
|
|
_recentSearchResultsDisposable = [[SMetaDisposable alloc] init];
|
|
|
|
__weak TGDialogListController *weakSelf = self;
|
|
[_recentSearchResultsDisposable setDisposable:[[[TGGlobalMessageSearchSignals recentPeerResults:^id (id item) {
|
|
__strong TGDialogListController *strongSelf = weakSelf;
|
|
if (strongSelf != nil)
|
|
return [strongSelf.dialogListCompanion processSearchResultItem:item];
|
|
return nil;
|
|
}] deliverOn:[SQueue mainQueue]] startWithNext:^(NSArray *peerResults)
|
|
{
|
|
__strong TGDialogListController *strongSelf = weakSelf;
|
|
if (strongSelf != nil)
|
|
{
|
|
NSMutableArray *searchResultsSections = [[NSMutableArray alloc] init];
|
|
|
|
if (peerResults.count != 0)
|
|
{
|
|
[searchResultsSections addObject:@{@"title": TGLocalized(@"DialogList.SearchSectionRecent"), @"items": peerResults, @"type": @"recent"}];
|
|
}
|
|
|
|
strongSelf->_recentSearchResultsSections = searchResultsSections;
|
|
strongSelf->_searchResultsSections = strongSelf->_recentSearchResultsSections;
|
|
}
|
|
}]];
|
|
|
|
[_searchMixin reloadSearchResults];
|
|
[_searchMixin setSearchResultsTableViewHidden:false animated:true];
|
|
}
|
|
|
|
- (void)searchMixinWillDeactivate:(bool)animated
|
|
{
|
|
_isDisplayingSearch = false;
|
|
_tableView.scrollEnabled = true;
|
|
|
|
[self setNavigationBarHidden:false animated:animated];
|
|
}
|
|
|
|
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
|
|
{
|
|
if (scrollView == _tableView)
|
|
{
|
|
_draggingStartOffset = scrollView.contentOffset.y;
|
|
}
|
|
|
|
if (_searchMixin.isActive && scrollView == _searchMixin.searchResultsTableView)
|
|
[_searchBar resignFirstResponder];
|
|
}
|
|
|
|
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)__unused velocity targetContentOffset:(inout CGPoint *)targetContentOffset
|
|
{
|
|
if (scrollView == _tableView)
|
|
{
|
|
if (targetContentOffset != NULL)
|
|
{
|
|
if (targetContentOffset->y > -_tableView.contentInset.top - FLT_EPSILON && targetContentOffset->y < -_tableView.contentInset.top + 44.0f + FLT_EPSILON)
|
|
{
|
|
if (_draggingStartOffset < -_tableView.contentInset.top + 22.0f)
|
|
{
|
|
if (targetContentOffset->y < -_tableView.contentInset.top + 44.0f * 0.2)
|
|
targetContentOffset->y = -_tableView.contentInset.top;
|
|
else
|
|
targetContentOffset->y = -_tableView.contentInset.top + 44.0f;
|
|
}
|
|
else
|
|
{
|
|
if (targetContentOffset->y < -_tableView.contentInset.top + 44.0f * 0.8)
|
|
targetContentOffset->y = -_tableView.contentInset.top;
|
|
else
|
|
targetContentOffset->y = -_tableView.contentInset.top + 44.0f;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#pragma mark -
|
|
|
|
- (void)searchDisplayControllerDidEndSearch:(UISearchDisplayController *)__unused controller
|
|
{
|
|
[_searchBar setSelectedScopeButtonIndex:0];
|
|
}
|
|
|
|
- (BOOL)searchDisplayController:(UISearchDisplayController *)__unused controller shouldReloadTableForSearchString:(NSString *)searchString
|
|
{
|
|
[_dialogListCompanion beginSearch:searchString inMessages:_searchBar.selectedScopeButtonIndex == 1];
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
- (void)searchDisplayController:(UISearchDisplayController *)__unused controller willShowSearchResultsTableView:(UITableView *)__unused tableView
|
|
{
|
|
tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
|
|
if (tableView.tableFooterView == nil)
|
|
tableView.tableFooterView = [[UIView alloc] init];
|
|
|
|
tableView.hidden = true;
|
|
}
|
|
|
|
- (void)searchDisplayController:(UISearchDisplayController *)__unused controller willHideSearchResultsTableView:(UITableView *)tableView
|
|
{
|
|
tableView.hidden = false;
|
|
}
|
|
|
|
- (BOOL)searchDisplayController:(UISearchDisplayController *)__unused controller shouldReloadTableForSearchScope:(NSInteger)searchOption
|
|
{
|
|
[_dialogListCompanion beginSearch:_searchBar.text inMessages:searchOption];
|
|
|
|
return false;
|
|
}
|
|
|
|
- (void)startSearch
|
|
{
|
|
[(TGListsTableView *)_tableView setBlockContentOffset:true];
|
|
[_searchBar becomeFirstResponder];
|
|
TGDispatchAfter(0.1f, dispatch_get_main_queue(), ^
|
|
{
|
|
[(TGListsTableView *)_tableView setBlockContentOffset:false];
|
|
_tableView.contentOffset = CGPointMake(0, -_tableView.contentInset.top);
|
|
});
|
|
}
|
|
|
|
- (void)actionStageActionRequested:(NSString *)action options:(NSDictionary *)options
|
|
{
|
|
if ([action isEqualToString:@"conversationMenuOpened"])
|
|
{
|
|
int64_t conversationId = [[options objectForKey:@"conversationId"] longLongValue];
|
|
for (NSIndexPath *indexPath in _tableView.indexPathsForVisibleRows)
|
|
{
|
|
UITableViewCell *cell = [_tableView cellForRowAtIndexPath:indexPath];
|
|
|
|
if ([cell isKindOfClass:[TGDialogListCell class]])
|
|
{
|
|
TGDialogListCell *dialogCell = (TGDialogListCell *)cell;
|
|
if (dialogCell.conversationId != conversationId)
|
|
{
|
|
[dialogCell dismissEditingControls:true];
|
|
}
|
|
|
|
[cell setSelected:false];
|
|
[cell setHighlighted:false];
|
|
}
|
|
}
|
|
|
|
if (_tableView.indexPathForSelectedRow != nil)
|
|
[_tableView deselectRowAtIndexPath:_tableView.indexPathForSelectedRow animated:false];
|
|
}
|
|
}
|
|
|
|
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)__unused editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
|
|
{
|
|
if (tableView == _tableView)
|
|
{
|
|
TGConversation *conversation = nil;
|
|
if (indexPath.row < (NSInteger)_listModel.count)
|
|
conversation = [_listModel objectAtIndex:indexPath.row];
|
|
|
|
if (conversation != nil)
|
|
{
|
|
if (true || conversation.isChat)
|
|
{
|
|
_conversationIdToDelete = conversation.conversationId;
|
|
|
|
_currentActionSheet.delegate = nil;
|
|
|
|
_currentActionSheet = [[UIActionSheet alloc] initWithTitle:nil delegate:self cancelButtonTitle:nil destructiveButtonTitle:nil otherButtonTitles:nil];
|
|
|
|
TGUser *user = conversation.conversationId > 0 ? [TGDatabaseInstance() loadUser:(int)conversation.conversationId] : nil;
|
|
|
|
if (conversation.conversationId > 0 && (user.kind == TGUserKindBot || user.kind == TGUserKindSmartBot))
|
|
{
|
|
[_currentActionSheet addButtonWithTitle:TGLocalized(@"DialogList.DeleteBotConfirmation")];
|
|
_currentActionSheet.destructiveButtonIndex = [_currentActionSheet addButtonWithTitle:TGLocalized(@"DialogList.DeleteBotConversationConfirmation")];
|
|
}
|
|
else
|
|
{
|
|
if (!conversation.isChannel) {
|
|
[_currentActionSheet addButtonWithTitle:TGLocalized(@"DialogList.ClearHistoryConfirmation")];
|
|
}
|
|
_currentActionSheet.destructiveButtonIndex = [_currentActionSheet addButtonWithTitle:(conversation.isBroadcast || !conversation.isChat) ? TGLocalized(@"Common.Delete") : TGLocalized(@"DialogList.DeleteConversationConfirmation")];
|
|
}
|
|
|
|
_currentActionSheet.cancelButtonIndex = [_currentActionSheet addButtonWithTitle:TGLocalized(@"Common.Cancel")];
|
|
|
|
[_currentActionSheet showInView:self.navigationController.view];
|
|
}
|
|
else
|
|
[_dialogListCompanion deleteItem:conversation animated:true];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
id result = [_searchResultsSections[indexPath.section][@"items"] objectAtIndex:indexPath.row];
|
|
int64_t peerId = 0;
|
|
if ([result isKindOfClass:[TGConversation class]])
|
|
peerId = ((TGConversation *)result).conversationId;
|
|
else if ([result isKindOfClass:[TGUser class]])
|
|
peerId = ((TGUser *)result).uid;
|
|
|
|
if (peerId != 0)
|
|
{
|
|
[TGGlobalMessageSearchSignals removeRecentPeerResult:peerId];
|
|
NSMutableArray *updatedSearchResultsSections = [[NSMutableArray alloc] initWithArray:_searchResultsSections];
|
|
NSMutableDictionary *updatedSection = [[NSMutableDictionary alloc] initWithDictionary:_searchResultsSections[indexPath.section]];
|
|
NSMutableArray *updatedItems = [[NSMutableArray alloc] initWithArray:updatedSection[@"items"]];
|
|
[updatedItems removeObjectAtIndex:indexPath.row];
|
|
if (updatedItems.count == 0)
|
|
{
|
|
[updatedSearchResultsSections removeObjectAtIndex:indexPath.section];
|
|
_searchResultsSections = updatedSearchResultsSections;
|
|
|
|
[tableView beginUpdates];
|
|
[tableView deleteSections:[NSIndexSet indexSetWithIndex:indexPath.section] withRowAnimation:UITableViewRowAnimationFade];
|
|
[tableView endUpdates];
|
|
}
|
|
else
|
|
{
|
|
updatedSection[@"items"] = updatedItems;
|
|
updatedSearchResultsSections[indexPath.section] = updatedSection;
|
|
_searchResultsSections = updatedSearchResultsSections;
|
|
|
|
[tableView beginUpdates];
|
|
[tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
|
|
[tableView endUpdates];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void)localizationUpdated
|
|
{
|
|
[_searchBar localizationUpdated];
|
|
|
|
[self setLeftBarButtonItem:[self controllerLeftBarButtonItem]];
|
|
|
|
[self setTitleText:TGLocalized(@"DialogList.Title")];
|
|
|
|
_titleLabel.text = TGLocalized(@"DialogList.Title");
|
|
[_titleLabel sizeToFit];
|
|
[self _layoutTitleViews:self.interfaceOrientation];
|
|
|
|
if (!_dialogListCompanion.forwardMode && !_dialogListCompanion.privacyMode)
|
|
_searchBar.customScopeButtonTitles = @[TGLocalized(@"DialogList.Conversations"), TGLocalized(@"DialogList.Messages")];
|
|
|
|
for (id cell in _tableView.visibleCells)
|
|
{
|
|
if ([cell isKindOfClass:[TGDialogListCell class]])
|
|
{
|
|
[(TGDialogListCell *)cell resetLocalization];
|
|
((TGDialogListCell *)cell).reuseTag = -1;
|
|
}
|
|
else if ([cell isKindOfClass:[TGDialogListBroadcastsMenuCell class]])
|
|
{
|
|
[(TGDialogListBroadcastsMenuCell *)cell resetLocalization];
|
|
}
|
|
}
|
|
|
|
[self reloadData];
|
|
}
|
|
|
|
- (void)tableView:(UITableView *)tableView didEndEditingRowAtIndexPath:(NSIndexPath *)__unused indexPath
|
|
{
|
|
if (tableView == _tableView && !tableView.editing)
|
|
{
|
|
[self selectCurrentConversation];
|
|
}
|
|
}
|
|
|
|
- (void)selectCurrentConversation
|
|
{
|
|
int index = -1;
|
|
for (TGConversation *conversation in _listModel)
|
|
{
|
|
index++;
|
|
if ([_dialogListCompanion isConversationOpened:conversation.conversationId])
|
|
{
|
|
[_tableView selectRowAtIndexPath:[NSIndexPath indexPathForRow:index inSection:1] animated:false scrollPosition:UITableViewScrollPositionNone];
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
|
|
{
|
|
if (tableView == _tableView)
|
|
return nil;
|
|
|
|
if (_searchResultsSections[section][@"title"] == nil)
|
|
return nil;
|
|
|
|
bool clear = false;
|
|
if ([_searchResultsSections[section][@"type"] isEqual:@"recent"])
|
|
clear = true;
|
|
|
|
return [self generateSectionHeader:_searchResultsSections[section][@"title"] first:false wide:true clear:clear];
|
|
}
|
|
|
|
- (UIView *)generateSectionHeader:(NSString *)title first:(bool)first wide:(bool)wide clear:(bool)clear
|
|
{
|
|
UIView *sectionContainer = nil;
|
|
|
|
NSMutableArray *reusableList = [_reusableSectionHeaders objectAtIndex:first ? 0 : 1];
|
|
|
|
for (UIView *view in reusableList)
|
|
{
|
|
if (view.superview == nil)
|
|
{
|
|
sectionContainer = view;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (sectionContainer == nil)
|
|
{
|
|
sectionContainer = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)];
|
|
|
|
sectionContainer.clipsToBounds = false;
|
|
sectionContainer.opaque = false;
|
|
|
|
UIView *sectionView = [[UIView alloc] initWithFrame:CGRectMake(0, first ? 0 : -1, 10, first ? 10 : 11)];
|
|
sectionView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
|
sectionView.backgroundColor = UIColorRGB(0xf7f7f7);
|
|
[sectionContainer addSubview:sectionView];
|
|
|
|
CGFloat separatorHeight = TGIsRetina() ? 0.5f : 1.0f;
|
|
UIView *separatorView = [[UIView alloc] initWithFrame:CGRectMake(0.0f, sectionView.frame.origin.y - (first ? separatorHeight : 0.0f), 10, separatorHeight)];
|
|
separatorView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
|
|
separatorView.backgroundColor = TGSeparatorColor();
|
|
[sectionContainer addSubview:separatorView];
|
|
|
|
UILabel *sectionLabel = [[UILabel alloc] init];
|
|
sectionLabel.tag = 100;
|
|
sectionLabel.backgroundColor = sectionView.backgroundColor;
|
|
sectionLabel.textColor = [UIColor blackColor];
|
|
sectionLabel.numberOfLines = 1;
|
|
|
|
[sectionContainer addSubview:sectionLabel];
|
|
|
|
[reusableList addObject:sectionContainer];
|
|
|
|
TGModernButton *clearButton = [[TGModernButton alloc] init];
|
|
clearButton.exclusiveTouch = true;
|
|
[clearButton setTitle:TGLocalized(@"WebSearch.RecentSectionClear") forState:UIControlStateNormal];
|
|
[clearButton setTitleColor:UIColorRGB(0x8e8e93)];
|
|
clearButton.titleLabel.font = TGSystemFontOfSize(14);
|
|
[clearButton sizeToFit];
|
|
CGRect clearButtonFrame = CGRectMake(0, 0, clearButton.frame.size.width + 14.0f, 28.0f);
|
|
clearButtonFrame.origin.x = sectionContainer.frame.size.width - clearButtonFrame.size.width;
|
|
clearButton.frame = clearButtonFrame;
|
|
clearButton.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin;
|
|
[clearButton setTag:200];
|
|
[clearButton addTarget:self action:@selector(clearRecentButtonPressed) forControlEvents:UIControlEventTouchUpInside];
|
|
[sectionContainer addSubview:clearButton];
|
|
}
|
|
|
|
UILabel *sectionLabel = (UILabel *)[sectionContainer viewWithTag:100];
|
|
sectionLabel.font = wide ? TGMediumSystemFontOfSize(14) : TGBoldSystemFontOfSize(17);
|
|
sectionLabel.text = title;
|
|
sectionLabel.textColor = wide ? UIColorRGB(0x8e8e93) : [UIColor blackColor];
|
|
[sectionLabel sizeToFit];
|
|
if (wide)
|
|
{
|
|
sectionLabel.frame = CGRectMake(8.0f, 4.0f + TGRetinaPixel, sectionLabel.frame.size.width, sectionLabel.frame.size.height);
|
|
}
|
|
else
|
|
{
|
|
sectionLabel.frame = CGRectMake(14.0f, TGRetinaPixel, sectionLabel.frame.size.width, sectionLabel.frame.size.height);
|
|
}
|
|
|
|
UIView *clearButton = [sectionContainer viewWithTag:200];
|
|
clearButton.hidden = !clear;
|
|
|
|
return sectionContainer;
|
|
}
|
|
|
|
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
|
|
{
|
|
if (tableView == _tableView)
|
|
return 0.0f;
|
|
|
|
if (((NSString *)_searchResultsSections[section][@"title"]).length == 0)
|
|
return 0.0f;
|
|
|
|
return 28.0f;
|
|
}
|
|
|
|
- (void)clearRecentButtonPressed
|
|
{
|
|
[TGGlobalMessageSearchSignals clearRecentResults];
|
|
[_recentSearchResultsDisposable setDisposable:nil];
|
|
_recentSearchResultsSections = nil;
|
|
_searchResultsSections = nil;
|
|
[_searchMixin reloadSearchResults];
|
|
}
|
|
|
|
- (void)updateSearchConversations:(NSArray *)conversations
|
|
{
|
|
if (_searchResultsSections.count != 0)
|
|
{
|
|
NSMutableDictionary *updatedConversations = [[NSMutableDictionary alloc] init];
|
|
for (TGConversation *conversation in conversations)
|
|
{
|
|
updatedConversations[@(conversation.conversationId)] = conversation;
|
|
}
|
|
|
|
NSMutableArray *updatedSearchResultsSections = [[NSMutableArray alloc] initWithArray:_searchResultsSections];
|
|
NSInteger index = -1;
|
|
for (NSDictionary *section in _searchResultsSections)
|
|
{
|
|
index++;
|
|
|
|
NSInteger itemIndex = -1;
|
|
NSMutableArray *updatedItems = nil;
|
|
for (id item in section[@"items"])
|
|
{
|
|
itemIndex++;
|
|
|
|
if ([item isKindOfClass:[TGConversation class]])
|
|
{
|
|
TGConversation *conversation = item;
|
|
TGConversation *updatedConversation = updatedConversations[@(conversation.conversationId)];
|
|
if (updatedConversation != nil)
|
|
{
|
|
if (updatedItems == nil)
|
|
updatedItems = [[NSMutableArray alloc] initWithArray:section[@"items"]];
|
|
|
|
[updatedItems replaceObjectAtIndex:itemIndex withObject:updatedConversation];
|
|
}
|
|
}
|
|
}
|
|
|
|
if (updatedItems != nil)
|
|
{
|
|
NSMutableDictionary *updatedSection = [[NSMutableDictionary alloc] initWithDictionary:section];
|
|
updatedSection[@"items"] = updatedItems;
|
|
updatedSearchResultsSections[index] = updatedSection;
|
|
}
|
|
}
|
|
_searchResultsSections = updatedSearchResultsSections;
|
|
|
|
for (id cell in _searchMixin.searchResultsTableView.visibleCells)
|
|
{
|
|
if ([cell isKindOfClass:[TGDialogListSearchCell class]])
|
|
{
|
|
TGDialogListSearchCell *searchCell = cell;
|
|
TGConversation *updatedConversation = updatedConversations[@(searchCell.conversationId)];
|
|
if (updatedConversation != nil)
|
|
{
|
|
searchCell.unreadCount = updatedConversation.unreadCount;
|
|
[searchCell resetView:false];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void)check3DTouch {
|
|
if (iosMajorVersion() >= 9) {
|
|
if (self.traitCollection.forceTouchCapability == UIForceTouchCapabilityAvailable) {
|
|
//[self registerForPreviewingWithDelegate:(id)self sourceView:self.view];
|
|
}
|
|
}
|
|
}
|
|
|
|
- (UIViewController *)previewingContext:(id<UIViewControllerPreviewing>)__unused previewingContext viewControllerForLocation:(CGPoint)location {
|
|
if (self.presentedViewController != nil) {
|
|
return nil;
|
|
}
|
|
|
|
CGPoint tablePoint = [self.view convertPoint:location toView:_tableView];
|
|
for (UITableViewCell *cell in _tableView.visibleCells) {
|
|
if ([cell isKindOfClass:[TGDialogListCell class]] && CGRectContainsPoint(cell.frame, tablePoint)) {
|
|
TGModernConversationController *controller = [[TGInterfaceManager instance] configuredConversationControlerWithId:((TGDialogListCell *)cell).conversationId];
|
|
return [TGNavigationController navigationControllerWithControllers:@[controller]];
|
|
}
|
|
}
|
|
|
|
return nil;
|
|
}
|
|
|
|
- (void)previewingContext:(id<UIViewControllerPreviewing>)__unused previewingContext commitViewController:(UIViewController *)viewControllerToCommit {
|
|
if ([viewControllerToCommit isKindOfClass:[TGNavigationController class]]) {
|
|
[TGAppDelegateInstance.rootController replaceContentController:[(TGNavigationController *)viewControllerToCommit viewControllers].firstObject];
|
|
}
|
|
}
|
|
|
|
@end
|
|
|