123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507 |
- // _____ _
- // |_ _| |_ _ _ ___ ___ _ __ __ _
- // | | | ' \| '_/ -_) -_) ' \/ _` |_
- // |_| |_||_|_| \___\___|_|_|_\__,_(_)
- //
- // Threema iOS Client
- // Copyright (c) 2012-2020 Threema GmbH
- //
- // This program is free software: you can redistribute it and/or modify
- // it under the terms of the GNU Affero General Public License, version 3,
- // as published by the Free Software Foundation.
- //
- // This program is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- // GNU Affero General Public License for more details.
- //
- // You should have received a copy of the GNU Affero General Public License
- // along with this program. If not, see <https://www.gnu.org/licenses/>.
- #import "ContactPickerViewController.h"
- #import "ContactCell.h"
- #import "GroupCell.h"
- #import "CreateGroupCell.h"
- #import "Contact.h"
- #import "ProtocolDefines.h"
- #import "AppDelegate.h"
- #import "ServerAPIConnector.h"
- #import "ErrorHandler.h"
- #import "EntityManager.h"
- #import "BundleUtil.h"
- #import "ContactTableDataSource.h"
- #import "GroupTableDataSource.h"
- #import "WorkContactTableDataSource.h"
- #import "ModalPresenter.h"
- #import "UserSettings.h"
- #import "LicenseStore.h"
- #import "ThemedTableViewController.h"
- #import "ModalNavigationController.h"
- #import "Threema-Swift.h"
- typedef enum : NSUInteger {
- ModeContacts,
- ModeGroups,
- ModeWorkContacts
- } Mode;
- @interface ContactPickerViewController ()
- @property Mode mode;
- @property id<ContactGroupDataSource> currentDataSource;
- @property (nonatomic) ContactTableDataSource *contactsDataSource;
- @property (nonatomic) GroupTableDataSource *groupsDataSource;
- @property (nonatomic) WorkContactTableDataSource *workContactsDataSource;
- @property (strong, nonatomic) UIView *statusBarView;
- @end
- @implementation ContactPickerViewController {
- NSMutableSet *groupContacts;
- BOOL groupMode;
- NSArray *filteredContacts;
- }
- - (id)initWithCoder:(NSCoder *)aDecoder {
- self = [super initWithCoder:aDecoder];
- if (self) {
- groupContacts = [NSMutableSet set];
- }
- return self;
- }
- - (void)viewDidLoad
- {
- [super viewDidLoad];
-
- _mode = ModeContacts;
- _currentDataSource = [self contactsDataSource];
-
- [self.segmentedControl setTitle:@"contacts" forSegmentAtIndex:ModeContacts];
- [self.segmentedControl setTitle:@"groups" forSegmentAtIndex:ModeGroups];
- if ([LicenseStore requiresLicenseKey]) {
- [self.segmentedControl insertSegmentWithTitle:@"work" atIndex:ModeWorkContacts animated:NO];
- if ([[self workContactsDataSource] numberOfSectionsInTableView:self.tableView] > 0) {
- // No regular contacts, so show Work contacts by default
- _mode = ModeWorkContacts;
- [self.segmentedControl setSelectedSegmentIndex:ModeWorkContacts];
- _currentDataSource = [self workContactsDataSource];
- }
- }
-
- for (int i = 0; i < self.segmentedControl.numberOfSegments; i++) {
- UIView *segment = self.segmentedControl.subviews[i];
- for (id subview in segment.subviews) {
- if ([subview isKindOfClass:[UILabel class]]) {
- UILabel *label = (UILabel *)subview;
- if ([label.text isEqualToString:@"contacts"]) {
- segment.accessibilityLabel = NSLocalizedString(@"segmentcontrol_contacts", @"");
- }
- else if ([label.text isEqualToString:@"groups"]) {
- segment.accessibilityLabel = NSLocalizedString(@"segmentcontrol_groups", @"");
- }
- else if ([label.text isEqualToString:@"work"]) {
- segment.accessibilityLabel = NSLocalizedString(@"segmentcontrol_work_contacts", @"");
- }
- }
- }
- }
- [self.segmentedControl setTitle:nil forSegmentAtIndex:ModeContacts];
- [self.segmentedControl setTitle:nil forSegmentAtIndex:ModeGroups];
- [self.segmentedControl setImage:[BundleUtil imageNamed:@"Contact"] forSegmentAtIndex:ModeContacts];
- [self.segmentedControl setImage:[BundleUtil imageNamed:@"Group"] forSegmentAtIndex:ModeGroups];
-
- if ([LicenseStore requiresLicenseKey]) {
- [self.segmentedControl setTitle:nil forSegmentAtIndex:ModeWorkContacts];
- [self.segmentedControl setImage:[BundleUtil imageNamed:@"Case"] forSegmentAtIndex:ModeWorkContacts];
- }
-
- self.searchController = [[UISearchController alloc]initWithSearchResultsController:nil];
- self.searchController.delegate = self;
- self.searchController.searchBar.showsScopeBar = NO;
- self.searchController.searchBar.scopeButtonTitles = nil;
- self.tableView.keyboardDismissMode = UIScrollViewKeyboardDismissModeOnDrag;
- self.searchController.searchBar.delegate = self;
- self.searchController.searchResultsUpdater = self;
- self.searchController.searchBar.autoresizingMask = UIViewAutoresizingFlexibleWidth;
- [self.searchController.searchBar sizeToFit];
- self.searchController.searchBar.barStyle = UISearchBarStyleMinimal;
- self.searchController.dimsBackgroundDuringPresentation = NO;
- self.definesPresentationContext = YES;
- self.searchController.hidesNavigationBarDuringPresentation = YES;
-
- if (@available(iOS 11.0, *)) {
- self.navigationItem.searchController = _searchController;
- } else {
- [self.view addSubview:self.searchController.searchBar];
- self.tableView.contentInset = UIEdgeInsetsMake(self.searchController.searchBar.frame.size.height, 0, 0, 0);
- self.statusBarView = [[UIView alloc] initWithFrame:[[UIApplication sharedApplication] statusBarFrame]];
- }
-
- [self setupColors];
-
- self.tableView.rowHeight = UITableViewAutomaticDimension;
- if (@available(iOS 11.0, *)) {
- self.tableView.estimatedRowHeight = UITableViewAutomaticDimension;
- } else {
- self.tableView.estimatedRowHeight = 44.0;
- }
- }
- - (void)setupColors {
- [self.view setBackgroundColor:[Colors backgroundLight]];
- [self.navigationController.view setBackgroundColor:[Colors background]];
-
- [Colors updateTableView:self.tableView];
-
- if (@available(iOS 11.0, *)) {
- self.searchController.searchBar.barTintColor = [UIColor clearColor];
- self.searchController.searchBar.backgroundColor = [UIColor clearColor];
-
- UINavigationBar *navigationBar = self.navigationController.navigationBar;
- if (navigationBar) {
- navigationBar.barTintColor = [Colors backgroundBaseColor];
- }
- } else {
- self.searchController.searchBar.backgroundColor = [Colors backgroundBaseColor];
-
- UINavigationBar *navigationBar = self.navigationController.navigationBar;
- if (navigationBar) {
- navigationBar.barTintColor = [Colors backgroundBaseColor];
- }
- }
-
- [Colors updateSearchBar:_searchController.searchBar];
- if (@available(iOS 11.0, *)) {
- self.searchController.searchBar.searchFieldBackgroundPositionAdjustment = UIOffsetMake(0.0, 7.0);
- self.navigationItem.largeTitleDisplayMode = [UserSettings sharedUserSettings].largeTitleDisplayMode;
- } else {
- [_statusBarView setBackgroundColor:[Colors searchBarStatusBar]];
- }
- }
- - (BOOL)shouldAutorotate {
- return YES;
- }
- -(UIInterfaceOrientationMask)supportedInterfaceOrientations {
- if (SYSTEM_IS_IPAD) {
- return UIInterfaceOrientationMaskAll;
- }
-
- return UIInterfaceOrientationMaskAllButUpsideDown;
- }
- #pragma mark - Table view
- - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
- [Colors updateTableViewCell:cell];
- }
- - (void)tableView:(UITableView *)tableView willDisplayHeaderView:(nonnull UIView *)view forSection:(NSInteger)section {
- UITableViewHeaderFooterView *headerView = (UITableViewHeaderFooterView*)view;
- [headerView.contentView setBackgroundColor:[Colors backgroundDark]];
- [headerView.textLabel setTextColor:[Colors fontNormal]];
- }
- - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
- return UITableViewAutomaticDimension;
- }
- -(CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath {
- return UITableViewAutomaticDimension;
- }
- - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
- if (_mode == ModeGroups) {
- return [self.currentDataSource numberOfSectionsInTableView:tableView] + 1;
- }
- if (_mode == ModeWorkContacts && [[UserSettings sharedUserSettings] companyDirectory] == true) {
- return [self.currentDataSource numberOfSectionsInTableView:tableView] + 1;
- }
- return [self.currentDataSource numberOfSectionsInTableView:tableView];
- }
- - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
- if (_mode == ModeGroups) {
- if (section == 0) {
- if (_searchController.searchBar.isFirstResponder) {
- return 0;
- }
-
- return 1;
- }
-
- return [self.currentDataSource tableView:tableView numberOfRowsInSection:section - 1];
- }
- if (_mode == ModeWorkContacts && [[UserSettings sharedUserSettings] companyDirectory] == true) {
- if (section == 0) {
- return 1;
- }
-
- return [self.currentDataSource tableView:tableView numberOfRowsInSection:section - 1];
- }
-
- return [self.currentDataSource tableView:tableView numberOfRowsInSection:section];
- }
- - (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
- return [self.currentDataSource sectionIndexTitlesForTableView:tableView];
- }
- - (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index {
- return [self.currentDataSource tableView:tableView sectionForSectionIndexTitle:title atIndex:index];
- }
- - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
- if (_mode == ModeGroups) {
- if (section == 1 && _searchController.searchBar.isFirstResponder == NO) {
- return NSLocalizedString(@"existing groups", nil);
- }
-
- return nil;
- }
- if (_mode == ModeWorkContacts && [[UserSettings sharedUserSettings] companyDirectory] == true) {
- return nil;
- }
-
- return [self.currentDataSource tableView:tableView titleForHeaderInSection:section];
- }
- - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
- {
- UITableViewCell *cell;
-
- if (_mode == ModeGroups) {
- if (indexPath.section == 0) {
- cell = [self.tableView dequeueReusableCellWithIdentifier:@"CreateGroupCell"];
- } else {
- NSIndexPath *convertedIndex = [NSIndexPath indexPathForRow:indexPath.row inSection:indexPath.section - 1];
- cell = [self tableView:tableView groupCellForIndexPath:convertedIndex];
- }
- }
- else if (_mode == ModeWorkContacts) {
- if ([[UserSettings sharedUserSettings] companyDirectory] == true) {
- if (indexPath.section == 0) {
- cell = [self.tableView dequeueReusableCellWithIdentifier:@"CompanyDirectoryCell"];
- [((CompanyDirectoryCell *)cell) setupColors];
- } else {
- NSIndexPath *convertedIndex = [NSIndexPath indexPathForRow:indexPath.row inSection:indexPath.section - 1];
- cell = [self tableView:tableView workContactCellForIndexPath:convertedIndex];
- }
- } else {
- NSIndexPath *convertedIndex = [NSIndexPath indexPathForRow:indexPath.row inSection:indexPath.section];
- cell = [self tableView:tableView workContactCellForIndexPath:convertedIndex];
- }
- }
- else {
- cell = [self tableView:tableView contactCellForIndexPath:indexPath];
- }
-
- return cell;
- }
- - (UITableViewCell *)tableView:(UITableView *)tableView contactCellForIndexPath:(NSIndexPath *)indexPath {
- ContactCell *cell = [self.tableView dequeueReusableCellWithIdentifier:@"ContactCell"];
-
- Contact *contact = [self.contactsDataSource contactAtIndexPath:indexPath];
- cell.contact = contact;
-
- return cell;
- }
- - (UITableViewCell *)tableView:(UITableView *)tableView groupCellForIndexPath:(NSIndexPath *)indexPath {
- GroupCell *cell = [self.tableView dequeueReusableCellWithIdentifier:@"GroupCell"];
-
- GroupProxy *group = [self.groupsDataSource groupAtIndexPath:indexPath];
- cell.group = group;
-
- return cell;
- }
- - (UITableViewCell *)tableView:(UITableView *)tableView workContactCellForIndexPath:(NSIndexPath *)indexPath {
- ContactCell *cell = [self.tableView dequeueReusableCellWithIdentifier:@"ContactCell"];
-
- Contact *contact = [self.workContactsDataSource workContactAtIndexPath:indexPath];
- cell.contact = contact;
-
- return cell;
- }
- - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
-
- UIViewController *presentingVC = self.presentingViewController;
- GroupProxy *group = nil;
- Contact *contact = nil;
-
- if (_mode == ModeGroups) {
- if (indexPath.section != 0) {
- NSIndexPath *convertedIndex = [NSIndexPath indexPathForRow:indexPath.row inSection:indexPath.section - 1];
- group = [((GroupTableDataSource *)_currentDataSource) groupAtIndexPath:convertedIndex];
- }
- }
- else if (_mode == ModeWorkContacts) {
- if ([[UserSettings sharedUserSettings] companyDirectory] == true) {
- if (indexPath.section != 0) {
- NSIndexPath *convertedIndex = [NSIndexPath indexPathForRow:indexPath.row inSection:indexPath.section - 1];
- contact = [((WorkContactTableDataSource *)_currentDataSource) workContactAtIndexPath:convertedIndex];
- }
- } else {
- contact = [((WorkContactTableDataSource *)_currentDataSource) workContactAtIndexPath:indexPath];
- }
- }
- else {
- contact = [((ContactTableDataSource *)_currentDataSource) contactAtIndexPath:indexPath];
- }
-
- [_searchController setActive:NO];
-
- [self dismissViewControllerAnimated:YES completion:^{
- if (_mode == ModeGroups) {
- if (indexPath.section == 0) {
- MDMSetup *mdmSetup = [[MDMSetup alloc] initWithSetup:NO];
- if ([mdmSetup disableCreateGroup]) {
- [UIAlertTemplate showAlertWithOwner:presentingVC title:@"" message:NSLocalizedString(@"disabled_by_device_policy", nil) actionOk:nil];
- } else {
- UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"CreateGroup" bundle:nil];
- UINavigationController *navVC = [storyboard instantiateInitialViewController];
-
- [presentingVC presentViewController:navVC animated:YES completion:nil];
- }
- } else {
- [self showConversationForGroup:group];
- }
- }
- else if (_mode == ModeWorkContacts && [[UserSettings sharedUserSettings] companyDirectory] == true) {
- if (indexPath.section == 0) {
- CompanyDirectoryViewController *companyDirectoryViewController = (CompanyDirectoryViewController *)[self.storyboard instantiateViewControllerWithIdentifier:@"CompanyDirectoryViewController"];
- companyDirectoryViewController.addContactActive = false;
- ModalNavigationController *nav = [[ModalNavigationController alloc] initWithRootViewController:companyDirectoryViewController];
- nav.showDoneButton = true;
- nav.showFullScreenOnIPad = false;
-
- [presentingVC presentViewController:nav animated:YES completion:nil];
-
-
-
- } else {
- [self showConversationForContact:contact];
- }
- }
- else {
- [self showConversationForContact:contact];
- }
- }];
- }
- - (void)showConversationForGroup:(GroupProxy *)group {
- Conversation *conversation = group.conversation;
- NSDictionary *info = [NSDictionary dictionaryWithObjectsAndKeys:
- conversation, kKeyConversation,
- [NSNumber numberWithBool:YES], kKeyForceCompose,
- nil];
- [[NSNotificationCenter defaultCenter] postNotificationName:kNotificationShowConversation object:nil
- userInfo:info];
- }
- - (void)showConversationForContact:(Contact *)contact {
- NSDictionary *info = [NSDictionary dictionaryWithObjectsAndKeys:
- contact, kKeyContact,
- [NSNumber numberWithBool:YES], kKeyForceCompose,
- nil];
- [[NSNotificationCenter defaultCenter] postNotificationName:kNotificationShowConversation object:nil
- userInfo:info];
- }
- - (IBAction)cancelAction:(id)sender {
- [self dismissViewControllerAnimated:YES completion:nil];
- }
- - (ContactTableDataSource *)contactsDataSource {
- if (_contactsDataSource == nil) {
- _contactsDataSource = [ContactTableDataSource contactTableDataSource];
- }
-
- return _contactsDataSource;
- }
- - (GroupTableDataSource *)groupsDataSource {
- if (_groupsDataSource == nil) {
- _groupsDataSource = [GroupTableDataSource groupTableDataSource];
- }
-
- return _groupsDataSource;
- }
- - (WorkContactTableDataSource *)workContactsDataSource {
- if (_workContactsDataSource == nil) {
- _workContactsDataSource = [WorkContactTableDataSource workContactTableDataSource];
- }
-
- return _workContactsDataSource;
- }
- #pragma mark - Search controller delegate
- - (void)willPresentSearchController:(UISearchController *)searchController {
- if (@available(iOS 11.0, *)) {
- self.searchController.searchBar.searchFieldBackgroundPositionAdjustment = UIOffsetMake(0.0, 0.0);
- } else {
- [self.searchController.view addSubview:_statusBarView];
- }
- }
- - (void)willDismissSearchController:(UISearchController *)searchController {
- if (@available(iOS 11.0, *)) {
- self.searchController.searchBar.searchFieldBackgroundPositionAdjustment = UIOffsetMake(0.0, 7.0);
- } else {
- [_statusBarView removeFromSuperview];
- }
- }
- -(void)updateSearchResultsForSearchController:(UISearchController *)searchController {
- [_currentDataSource filterByWords: [self searchWordsForText:_searchController.searchBar.text]];
- [self.tableView reloadData];
- }
- - (NSArray *)searchWordsForText:(NSString *)text {
- NSArray *searchWords = nil;
- if (text && [text length] > 0) {
- searchWords = [text componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
- }
-
- return searchWords;
- }
- #pragma mark - Actions
- - (IBAction)segmentedControlChanged:(id)sender {
- _mode = self.segmentedControl.selectedSegmentIndex;
-
- switch (_mode) {
- case ModeContacts:
- _currentDataSource = [self contactsDataSource];
- [_currentDataSource filterByWords: [self searchWordsForText:_searchController.searchBar.text]];
- break;
-
- case ModeGroups:
- _currentDataSource = [self groupsDataSource];
- [_currentDataSource filterByWords: [self searchWordsForText:_searchController.searchBar.text]];
- break;
-
- case ModeWorkContacts:
- _currentDataSource = [self workContactsDataSource];
- [_currentDataSource filterByWords: [self searchWordsForText:_searchController.searchBar.text]];
- break;
-
- default:
- break;
- }
-
- [self.tableView reloadData];
- }
- @end
|