mirror of
https://gitlab.opencode.de/bwi/bundesmessenger/clients/bundesmessenger-ios.git
synced 2026-05-02 06:06:57 +02:00
Structure project almost by features. Start by organizing view controllers.
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
Copyright 2016 OpenMarket Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#import "ContactsTableViewController.h"
|
||||
|
||||
/**
|
||||
'StartChatViewController' instance is used to prepare new room creation.
|
||||
*/
|
||||
@interface StartChatViewController : ContactsTableViewController <UITableViewDataSource, UISearchBarDelegate, ContactsTableViewControllerDelegate>
|
||||
|
||||
@property (weak, nonatomic) IBOutlet UIView *searchBarHeader;
|
||||
@property (weak, nonatomic) IBOutlet UISearchBar *searchBarView;
|
||||
@property (weak, nonatomic) IBOutlet UIView *searchBarHeaderBorder;
|
||||
|
||||
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *searchBarTopConstraint;
|
||||
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *tableViewBottomConstraint;
|
||||
|
||||
/**
|
||||
Tell whether a search session is in progress
|
||||
*/
|
||||
@property (nonatomic) BOOL isAddParticipantSearchBarEditing;
|
||||
|
||||
/**
|
||||
Returns the `UINib` object initialized for a `StartChatViewController`.
|
||||
|
||||
@return The initialized `UINib` object or `nil` if there were errors during initialization
|
||||
or the nib file could not be located.
|
||||
*/
|
||||
+ (UINib *)nib;
|
||||
|
||||
/**
|
||||
Creates and returns a new `StartChatViewController` object.
|
||||
|
||||
@discussion This is the designated initializer for programmatic instantiation.
|
||||
@return An initialized `StartChatViewController` object if successful, `nil` otherwise.
|
||||
*/
|
||||
+ (instancetype)startChatViewController;
|
||||
|
||||
@end
|
||||
|
||||
@@ -0,0 +1,692 @@
|
||||
/*
|
||||
Copyright 2016 OpenMarket Ltd
|
||||
Copyright 2017 Vector Creations Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#import "StartChatViewController.h"
|
||||
|
||||
#import "AppDelegate.h"
|
||||
|
||||
@interface StartChatViewController ()
|
||||
{
|
||||
// The contact used to describe the current user.
|
||||
MXKContact *userContact;
|
||||
|
||||
// Section indexes
|
||||
NSInteger participantsSection;
|
||||
|
||||
// The current list of participants.
|
||||
NSMutableArray<MXKContact*> *participants;
|
||||
|
||||
// Navigation bar items
|
||||
UIBarButtonItem *cancelBarButtonItem;
|
||||
UIBarButtonItem *createBarButtonItem;
|
||||
|
||||
// HTTP Request
|
||||
MXHTTPOperation *roomCreationRequest;
|
||||
|
||||
// This dictionary tells for each display name whether it appears several times in participants list
|
||||
NSMutableDictionary <NSString*, NSNumber*> *isMultiUseNameByDisplayName;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation StartChatViewController
|
||||
|
||||
#pragma mark - Class methods
|
||||
|
||||
+ (UINib *)nib
|
||||
{
|
||||
return [UINib nibWithNibName:NSStringFromClass([StartChatViewController class])
|
||||
bundle:[NSBundle bundleForClass:[StartChatViewController class]]];
|
||||
}
|
||||
|
||||
+ (instancetype)startChatViewController
|
||||
{
|
||||
return [[[self class] alloc] initWithNibName:NSStringFromClass([StartChatViewController class])
|
||||
bundle:[NSBundle bundleForClass:[StartChatViewController class]]];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (void)finalizeInit
|
||||
{
|
||||
[super finalizeInit];
|
||||
|
||||
self.screenName = @"StartChat";
|
||||
|
||||
_isAddParticipantSearchBarEditing = NO;
|
||||
|
||||
// Prepare room participants
|
||||
participants = [NSMutableArray array];
|
||||
|
||||
// Assign itself as delegate
|
||||
self.contactsTableViewControllerDelegate = self;
|
||||
}
|
||||
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
// Do any additional setup after loading the view, typically from a nib.
|
||||
|
||||
// Adjust Top and Bottom constraints to take into account potential navBar and tabBar.
|
||||
[NSLayoutConstraint deactivateConstraints:@[_searchBarTopConstraint, _tableViewBottomConstraint]];
|
||||
|
||||
_searchBarTopConstraint = [NSLayoutConstraint constraintWithItem:self.topLayoutGuide
|
||||
attribute:NSLayoutAttributeBottom
|
||||
relatedBy:NSLayoutRelationEqual
|
||||
toItem:self.searchBarHeader
|
||||
attribute:NSLayoutAttributeTop
|
||||
multiplier:1.0f
|
||||
constant:0.0f];
|
||||
|
||||
_tableViewBottomConstraint = [NSLayoutConstraint constraintWithItem:self.bottomLayoutGuide
|
||||
attribute:NSLayoutAttributeTop
|
||||
relatedBy:NSLayoutRelationEqual
|
||||
toItem:self.contactsTableView
|
||||
attribute:NSLayoutAttributeBottom
|
||||
multiplier:1.0f
|
||||
constant:0.0f];
|
||||
|
||||
[NSLayoutConstraint activateConstraints:@[_searchBarTopConstraint, _tableViewBottomConstraint]];
|
||||
|
||||
self.navigationItem.title = NSLocalizedStringFromTable(@"room_creation_title", @"Vector", nil);
|
||||
|
||||
// Add each matrix session by default.
|
||||
NSArray *sessions = [AppDelegate theDelegate].mxSessions;
|
||||
for (MXSession *mxSession in sessions)
|
||||
{
|
||||
[self addMatrixSession:mxSession];
|
||||
}
|
||||
|
||||
// Prepare its data source
|
||||
ContactsDataSource *dataSource = [[ContactsDataSource alloc] initWithMatrixSession:self.mainSession]; // TO TEST
|
||||
dataSource.areSectionsShrinkable = YES;
|
||||
dataSource.displaySearchInputInContactsList = YES;
|
||||
dataSource.forceMatrixIdInDisplayName = YES;
|
||||
// Add a plus icon to the contact cell when a search session is in progress,
|
||||
// in order to make it more understandable for the end user.
|
||||
dataSource.contactCellAccessoryImage = [UIImage imageNamed:@"plus_icon"];
|
||||
|
||||
[self displayList:dataSource];
|
||||
|
||||
cancelBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(onButtonPressed:)];
|
||||
self.navigationItem.leftBarButtonItem = cancelBarButtonItem;
|
||||
|
||||
createBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:NSLocalizedStringFromTable(@"start", @"Vector", nil) style:UIBarButtonItemStylePlain target:self action:@selector(onButtonPressed:)];
|
||||
self.navigationItem.rightBarButtonItem = createBarButtonItem;
|
||||
|
||||
_searchBarView.placeholder = NSLocalizedStringFromTable(@"room_creation_invite_another_user", @"Vector", nil);
|
||||
_searchBarView.returnKeyType = UIReturnKeyDone;
|
||||
_searchBarView.autocapitalizationType = UITextAutocapitalizationTypeNone;
|
||||
[self refreshSearchBarItemsColor:_searchBarView];
|
||||
|
||||
// Hide line separators of empty cells
|
||||
self.contactsTableView.tableFooterView = [[UIView alloc] init];
|
||||
|
||||
[self.contactsTableView registerClass:ContactTableViewCell.class forCellReuseIdentifier:@"ParticipantTableViewCellId"];
|
||||
|
||||
// Redirect table data source
|
||||
self.contactsTableView.dataSource = self;
|
||||
}
|
||||
|
||||
- (void)userInterfaceThemeDidChange
|
||||
{
|
||||
[super userInterfaceThemeDidChange];
|
||||
|
||||
[self refreshSearchBarItemsColor:_searchBarView];
|
||||
|
||||
_searchBarHeaderBorder.backgroundColor = kRiotAuxiliaryColor;
|
||||
|
||||
// Check the table view style to select its bg color.
|
||||
self.contactsTableView.backgroundColor = ((self.contactsTableView.style == UITableViewStylePlain) ? kRiotPrimaryBgColor : kRiotSecondaryBgColor);
|
||||
self.view.backgroundColor = self.contactsTableView.backgroundColor;
|
||||
|
||||
if (self.contactsTableView.dataSource)
|
||||
{
|
||||
[self.contactsTableView reloadData];
|
||||
}
|
||||
}
|
||||
|
||||
- (UIStatusBarStyle)preferredStatusBarStyle
|
||||
{
|
||||
return kRiotDesignStatusBarStyle;
|
||||
}
|
||||
|
||||
- (void)destroy
|
||||
{
|
||||
if (roomCreationRequest)
|
||||
{
|
||||
[roomCreationRequest cancel];
|
||||
roomCreationRequest = nil;
|
||||
}
|
||||
|
||||
cancelBarButtonItem = nil;
|
||||
createBarButtonItem = nil;
|
||||
|
||||
isMultiUseNameByDisplayName = nil;
|
||||
|
||||
participants = nil;
|
||||
|
||||
[super destroy];
|
||||
}
|
||||
|
||||
- (void)addMatrixSession:(MXSession *)mxSession
|
||||
{
|
||||
[super addMatrixSession:mxSession];
|
||||
|
||||
// FIXME: Handle multi accounts
|
||||
NSString *displayName = NSLocalizedStringFromTable(@"you", @"Vector", nil);
|
||||
userContact = [[MXKContact alloc] initMatrixContactWithDisplayName:displayName andMatrixID:self.mainSession.myUser.userId];
|
||||
|
||||
[self refreshParticipants];
|
||||
}
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated
|
||||
{
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
// Active the search session if the current participant list is empty
|
||||
if (!participants.count)
|
||||
{
|
||||
self.isAddParticipantSearchBarEditing = YES;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Refresh display
|
||||
[self refreshContactsTable];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)viewWillDisappear:(BOOL)animated
|
||||
{
|
||||
[super viewWillDisappear:animated];
|
||||
|
||||
// cancel any pending search
|
||||
[self searchBarCancelButtonClicked:_searchBarView];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (void)setIsAddParticipantSearchBarEditing:(BOOL)isAddParticipantSearchBarEditing
|
||||
{
|
||||
if (_isAddParticipantSearchBarEditing != isAddParticipantSearchBarEditing)
|
||||
{
|
||||
if (isAddParticipantSearchBarEditing)
|
||||
{
|
||||
self.navigationItem.rightBarButtonItem = nil;
|
||||
}
|
||||
else
|
||||
{
|
||||
self.navigationItem.rightBarButtonItem = createBarButtonItem;
|
||||
|
||||
[self refreshParticipants];
|
||||
}
|
||||
|
||||
_isAddParticipantSearchBarEditing = isAddParticipantSearchBarEditing;
|
||||
|
||||
// Switch the display between search result and participants list
|
||||
[self refreshContactsTable];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Internals
|
||||
|
||||
- (void)refreshParticipants
|
||||
{
|
||||
// Refer all participants in ignored contacts dictionary.
|
||||
isMultiUseNameByDisplayName = [NSMutableDictionary dictionary];
|
||||
[contactsDataSource.ignoredContactsByMatrixId removeAllObjects];
|
||||
[contactsDataSource.ignoredContactsByEmail removeAllObjects];
|
||||
|
||||
for (MXKContact* contact in participants)
|
||||
{
|
||||
NSArray *identifiers = contact.matrixIdentifiers;
|
||||
if (identifiers.count)
|
||||
{
|
||||
// Here the contact can only have one identifier
|
||||
[contactsDataSource.ignoredContactsByMatrixId setObject:contact forKey:identifiers.firstObject];
|
||||
}
|
||||
else
|
||||
{
|
||||
NSArray *emails = contact.emailAddresses;
|
||||
if (emails.count)
|
||||
{
|
||||
// Here the contact can only have one email
|
||||
MXKEmail *email = emails.firstObject;
|
||||
[contactsDataSource.ignoredContactsByEmail setObject:contact forKey:email.emailAddress];
|
||||
}
|
||||
}
|
||||
isMultiUseNameByDisplayName[contact.displayName] = (isMultiUseNameByDisplayName[contact.displayName] ? @(YES) : @(NO));
|
||||
}
|
||||
|
||||
if (userContact)
|
||||
{
|
||||
[contactsDataSource.ignoredContactsByMatrixId setObject:userContact forKey:self.mainSession.myUser.userId];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - UITableView data source
|
||||
|
||||
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
|
||||
{
|
||||
NSInteger count = 0;
|
||||
|
||||
if (_isAddParticipantSearchBarEditing)
|
||||
{
|
||||
participantsSection = -1;
|
||||
count = [contactsDataSource numberOfSectionsInTableView:tableView];
|
||||
}
|
||||
else
|
||||
{
|
||||
participantsSection = count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
|
||||
{
|
||||
NSInteger count = 0;
|
||||
|
||||
if (_isAddParticipantSearchBarEditing)
|
||||
{
|
||||
count = [contactsDataSource tableView:tableView numberOfRowsInSection:section];
|
||||
}
|
||||
else if (section == participantsSection)
|
||||
{
|
||||
count = participants.count + 1;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
UITableViewCell *cell;
|
||||
|
||||
if (_isAddParticipantSearchBarEditing)
|
||||
{
|
||||
cell = [contactsDataSource tableView:tableView cellForRowAtIndexPath:indexPath];
|
||||
}
|
||||
else if (indexPath.section == participantsSection)
|
||||
{
|
||||
ContactTableViewCell* participantCell = [tableView dequeueReusableCellWithIdentifier:@"ParticipantTableViewCellId" forIndexPath:indexPath];
|
||||
|
||||
MXKContact *contact;
|
||||
|
||||
if (indexPath.row == 0)
|
||||
{
|
||||
// oneself dedicated cell
|
||||
contact = userContact;
|
||||
}
|
||||
else
|
||||
{
|
||||
NSInteger index = indexPath.row - 1;
|
||||
|
||||
if (index < participants.count)
|
||||
{
|
||||
contact = participants[index];
|
||||
|
||||
// Disambiguate the display name when it appears several times.
|
||||
if (contact.displayName)
|
||||
{
|
||||
participantCell.showMatrixIdInDisplayName = [isMultiUseNameByDisplayName[contact.displayName] isEqualToNumber:@(YES)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
participantCell.selectionStyle = UITableViewCellSelectionStyleNone;
|
||||
[participantCell render:contact];
|
||||
|
||||
cell = participantCell;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Return a fake cell to prevent app from crashing.
|
||||
cell = [[UITableViewCell alloc] init];
|
||||
}
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
if (indexPath.section == participantsSection && indexPath.row != 0)
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void)tableView:(UITableView*)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath*)indexPath
|
||||
{
|
||||
// iOS8 requires this method to enable editing (see editActionsForRowAtIndexPath).
|
||||
}
|
||||
|
||||
#pragma mark - UITableView delegate
|
||||
|
||||
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath;
|
||||
{
|
||||
cell.backgroundColor = kRiotPrimaryBgColor;
|
||||
|
||||
// Update the selected background view
|
||||
if (kRiotSelectedBgColor)
|
||||
{
|
||||
cell.selectedBackgroundView = [[UIView alloc] init];
|
||||
cell.selectedBackgroundView.backgroundColor = kRiotSelectedBgColor;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (tableView.style == UITableViewStylePlain)
|
||||
{
|
||||
cell.selectedBackgroundView = nil;
|
||||
}
|
||||
else
|
||||
{
|
||||
cell.selectedBackgroundView.backgroundColor = nil;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
|
||||
{
|
||||
CGFloat height = 0.0;
|
||||
|
||||
if (_isAddParticipantSearchBarEditing)
|
||||
{
|
||||
height = [contactsDataSource heightForHeaderInSection:section];
|
||||
}
|
||||
|
||||
return height;
|
||||
}
|
||||
|
||||
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
if (_isAddParticipantSearchBarEditing)
|
||||
{
|
||||
return [super tableView:tableView heightForRowAtIndexPath:indexPath];
|
||||
}
|
||||
|
||||
return 74;
|
||||
}
|
||||
|
||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
if (_isAddParticipantSearchBarEditing)
|
||||
{
|
||||
[super tableView:tableView didSelectRowAtIndexPath:indexPath];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Do nothing
|
||||
[tableView deselectRowAtIndexPath:indexPath animated:YES];
|
||||
}
|
||||
}
|
||||
|
||||
- (NSArray *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
NSMutableArray* actions;
|
||||
|
||||
// add the swipe to delete only on participants sections
|
||||
if (indexPath.section == participantsSection && indexPath.row != 0)
|
||||
{
|
||||
actions = [[NSMutableArray alloc] init];
|
||||
|
||||
// Patch: Force the width of the button by adding whitespace characters into the title string.
|
||||
UITableViewRowAction *leaveAction = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDestructive title:@" " handler:^(UITableViewRowAction *action, NSIndexPath *indexPath){
|
||||
|
||||
[self onDeleteAt:indexPath];
|
||||
|
||||
}];
|
||||
|
||||
leaveAction.backgroundColor = [MXKTools convertImageToPatternColor:@"remove_icon" backgroundColor:kRiotSecondaryBgColor patternSize:CGSizeMake(74, 74) resourceSize:CGSizeMake(24, 24)];
|
||||
[actions insertObject:leaveAction atIndex:0];
|
||||
}
|
||||
|
||||
return actions;
|
||||
}
|
||||
|
||||
#pragma mark - Actions
|
||||
|
||||
- (void)onDeleteAt:(NSIndexPath*)path
|
||||
{
|
||||
NSInteger row = path.row;
|
||||
row --;
|
||||
|
||||
if (row < participants.count)
|
||||
{
|
||||
[participants removeObjectAtIndex:row];
|
||||
|
||||
[self refreshParticipants];
|
||||
|
||||
[self refreshContactsTable];
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)onButtonPressed:(id)sender
|
||||
{
|
||||
if (sender == createBarButtonItem)
|
||||
{
|
||||
// Disable button to prevent multiple request
|
||||
createBarButtonItem.enabled = NO;
|
||||
[self startActivityIndicator];
|
||||
|
||||
// Prepare the invited participant data
|
||||
NSMutableArray *inviteArray = [NSMutableArray array];
|
||||
NSMutableArray *invite3PIDArray = [NSMutableArray array];
|
||||
|
||||
// Check whether some users must be invited
|
||||
for (MXKContact *contact in participants)
|
||||
{
|
||||
NSArray *identifiers = contact.matrixIdentifiers;
|
||||
if (identifiers.count)
|
||||
{
|
||||
[inviteArray addObject:identifiers.firstObject];
|
||||
}
|
||||
else
|
||||
{
|
||||
// This is a text entered by the user, or a local contact
|
||||
NSString *participantId;
|
||||
|
||||
if (contact.emailAddresses.count)
|
||||
{
|
||||
// This is a local contact, consider the first email by default.
|
||||
// TODO: Prompt the user to select the right email.
|
||||
MXKEmail *email = contact.emailAddresses.firstObject;
|
||||
participantId = email.emailAddress;
|
||||
}
|
||||
else
|
||||
{
|
||||
// This is the text filled by the user.
|
||||
participantId = contact.displayName;
|
||||
}
|
||||
|
||||
// Is it an email or a Matrix user ID?
|
||||
if ([MXTools isEmailAddress:participantId])
|
||||
{
|
||||
// The identity server must be defined
|
||||
if (!self.mainSession.matrixRestClient.identityServer)
|
||||
{
|
||||
MXError *error = [[MXError alloc] initWithErrorCode:kMXSDKErrCodeStringMissingParameters error:@"No supplied identity server URL"];
|
||||
NSLog(@"[StartChatViewController] Invite %@ failed", participantId);
|
||||
// Alert user
|
||||
[[AppDelegate theDelegate] showErrorAsAlert:[error createNSError]];
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// The hostname of the identity server must not have the protocol part
|
||||
NSString *identityServer = self.mainSession.matrixRestClient.identityServer;
|
||||
if ([identityServer hasPrefix:@"http://"] || [identityServer hasPrefix:@"https://"])
|
||||
{
|
||||
identityServer = [identityServer substringFromIndex:[identityServer rangeOfString:@"://"].location + 3];
|
||||
}
|
||||
|
||||
MXInvite3PID *invite3PID = [[MXInvite3PID alloc] init];
|
||||
invite3PID.identityServer = identityServer;
|
||||
invite3PID.medium = kMX3PIDMediumEmail;
|
||||
invite3PID.address = participantId;
|
||||
|
||||
[invite3PIDArray addObject:invite3PID];
|
||||
}
|
||||
else
|
||||
{
|
||||
[inviteArray addObject:participantId];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Is it a direct chat?
|
||||
BOOL isDirect = ((inviteArray.count + invite3PIDArray.count == 1) ? YES : NO);
|
||||
|
||||
// In case of a direct chat with only one user id, we open the first available direct chat
|
||||
// or creates a new one (if it doesn't exist).
|
||||
if (isDirect && inviteArray.count)
|
||||
{
|
||||
[[AppDelegate theDelegate] startDirectChatWithUserId:inviteArray.firstObject completion:^{
|
||||
|
||||
[self stopActivityIndicator];
|
||||
|
||||
}];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Ensure direct chat are created with equal ops on both sides (the trusted_private_chat preset)
|
||||
MXRoomPreset preset = (isDirect ? kMXRoomPresetTrustedPrivateChat : nil);
|
||||
|
||||
// Create new room
|
||||
roomCreationRequest = [self.mainSession createRoom:nil
|
||||
visibility:kMXRoomDirectoryVisibilityPrivate
|
||||
roomAlias:nil
|
||||
topic:nil
|
||||
invite:(inviteArray.count ? inviteArray : nil)
|
||||
invite3PID:(invite3PIDArray.count ? invite3PIDArray : nil)
|
||||
isDirect:isDirect
|
||||
preset:preset
|
||||
success:^(MXRoom *room) {
|
||||
|
||||
roomCreationRequest = nil;
|
||||
|
||||
[self stopActivityIndicator];
|
||||
|
||||
[[AppDelegate theDelegate] showRoom:room.state.roomId andEventId:nil withMatrixSession:self.mainSession];
|
||||
|
||||
} failure:^(NSError *error) {
|
||||
|
||||
createBarButtonItem.enabled = YES;
|
||||
|
||||
roomCreationRequest = nil;
|
||||
[self stopActivityIndicator];
|
||||
|
||||
NSLog(@"[StartChatViewController] Create room failed");
|
||||
|
||||
// Alert user
|
||||
[[AppDelegate theDelegate] showErrorAsAlert:error];
|
||||
|
||||
}];
|
||||
}
|
||||
}
|
||||
else if (sender == self.navigationItem.leftBarButtonItem)
|
||||
{
|
||||
// Cancel has been pressed
|
||||
if (_isAddParticipantSearchBarEditing && participants.count)
|
||||
{
|
||||
// Cancel the search process
|
||||
[self searchBarCancelButtonClicked:_searchBarView];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Cancel the new chat creation
|
||||
[self.navigationController dismissViewControllerAnimated:YES completion:nil];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - UISearchBar delegate
|
||||
|
||||
- (void)refreshSearchBarItemsColor:(UISearchBar *)searchBar
|
||||
{
|
||||
// bar tint color
|
||||
searchBar.barTintColor = searchBar.tintColor = kRiotColorGreen;
|
||||
searchBar.tintColor = kRiotColorGreen;
|
||||
|
||||
// FIXME: this all seems incredibly fragile and tied to gutwrenching the current UISearchBar internals.
|
||||
|
||||
// text color
|
||||
UITextField *searchBarTextField = [searchBar valueForKey:@"_searchField"];
|
||||
searchBarTextField.textColor = kRiotSecondaryTextColor;
|
||||
|
||||
// Magnifying glass icon.
|
||||
UIImageView *leftImageView = (UIImageView *)searchBarTextField.leftView;
|
||||
leftImageView.image = [leftImageView.image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
|
||||
leftImageView.tintColor = kRiotColorGreen;
|
||||
|
||||
// remove the gray background color
|
||||
UIView *effectBackgroundTop = [searchBarTextField valueForKey:@"_effectBackgroundTop"];
|
||||
UIView *effectBackgroundBottom = [searchBarTextField valueForKey:@"_effectBackgroundBottom"];
|
||||
effectBackgroundTop.hidden = YES;
|
||||
effectBackgroundBottom.hidden = YES;
|
||||
|
||||
// place holder
|
||||
if (searchBarTextField.placeholder)
|
||||
{
|
||||
searchBarTextField.attributedPlaceholder = [[NSAttributedString alloc] initWithString:searchBarTextField.placeholder
|
||||
attributes:@{NSUnderlineStyleAttributeName: @(NSUnderlineStyleSingle),
|
||||
NSUnderlineColorAttributeName: kRiotColorGreen,
|
||||
NSForegroundColorAttributeName: kRiotColorGreen}];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
|
||||
{
|
||||
[contactsDataSource searchWithPattern:searchText forceReset:NO];
|
||||
}
|
||||
|
||||
- (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar
|
||||
{
|
||||
self.isAddParticipantSearchBarEditing = YES;
|
||||
searchBar.showsCancelButton = NO;
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar
|
||||
{
|
||||
searchBar.text = nil;
|
||||
self.isAddParticipantSearchBarEditing = NO;
|
||||
|
||||
// Reset filtering
|
||||
[contactsDataSource searchWithPattern:nil forceReset:NO];
|
||||
|
||||
// Leave search
|
||||
[searchBar resignFirstResponder];
|
||||
}
|
||||
|
||||
#pragma mark - ContactsTableViewControllerDelegate
|
||||
|
||||
- (void)contactsTableViewController:(ContactsTableViewController *)contactsTableViewController didSelectContact:(MXKContact*)contact
|
||||
{
|
||||
if (contact)
|
||||
{
|
||||
// Update here the mutable list of participants
|
||||
[participants addObject:contact];
|
||||
}
|
||||
|
||||
// Refresh display by leaving search session
|
||||
[self searchBarCancelButtonClicked:_searchBarView];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,86 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="12121" systemVersion="16F73" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
|
||||
<device id="retina4_7" orientation="portrait">
|
||||
<adaptation id="fullscreen"/>
|
||||
</device>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="StartChatViewController">
|
||||
<connections>
|
||||
<outlet property="contactsTableView" destination="kNf-Ll-jvH" id="PDi-bW-2CG"/>
|
||||
<outlet property="searchBarHeader" destination="Zm7-AB-ZtE" id="6ee-P0-twi"/>
|
||||
<outlet property="searchBarHeaderBorder" destination="gcy-W7-89G" id="tsy-SP-KaJ"/>
|
||||
<outlet property="searchBarTopConstraint" destination="sUb-hD-qXJ" id="rzi-JJ-nnP"/>
|
||||
<outlet property="searchBarView" destination="bsq-3U-VjV" id="x3M-wX-RW8"/>
|
||||
<outlet property="tableViewBottomConstraint" destination="jLY-ml-Psl" id="Q2b-sC-Yqn"/>
|
||||
<outlet property="view" destination="iN0-l3-epB" id="csR-cn-S4h"/>
|
||||
</connections>
|
||||
</placeholder>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<view contentMode="scaleToFill" id="iN0-l3-epB">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Zm7-AB-ZtE">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="50"/>
|
||||
<subviews>
|
||||
<searchBar contentMode="redraw" searchBarStyle="minimal" translatesAutoresizingMaskIntoConstraints="NO" id="bsq-3U-VjV">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="50"/>
|
||||
<textInputTraits key="textInputTraits" returnKeyType="done"/>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="accessibilityIdentifier" value="StartChatVCSearchBarView"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
<connections>
|
||||
<outlet property="delegate" destination="-1" id="UYv-bz-JBZ"/>
|
||||
</connections>
|
||||
</searchBar>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="gcy-W7-89G">
|
||||
<rect key="frame" x="0.0" y="49" width="375" height="1"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="1" id="Rka-an-qn3"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||
<accessibility key="accessibilityConfiguration" identifier="StartChatVCSearchBar"/>
|
||||
<constraints>
|
||||
<constraint firstItem="gcy-W7-89G" firstAttribute="leading" secondItem="Zm7-AB-ZtE" secondAttribute="leading" id="4Yn-dN-O2U"/>
|
||||
<constraint firstItem="bsq-3U-VjV" firstAttribute="leading" secondItem="Zm7-AB-ZtE" secondAttribute="leading" id="6ze-Az-ymf"/>
|
||||
<constraint firstAttribute="bottom" secondItem="bsq-3U-VjV" secondAttribute="bottom" id="KDW-SI-sG6"/>
|
||||
<constraint firstAttribute="trailing" secondItem="bsq-3U-VjV" secondAttribute="trailing" id="ZlE-SL-UfQ"/>
|
||||
<constraint firstAttribute="trailing" secondItem="gcy-W7-89G" secondAttribute="trailing" id="hqD-vA-OM5"/>
|
||||
<constraint firstAttribute="bottom" secondItem="gcy-W7-89G" secondAttribute="bottom" id="ibU-h7-mHt"/>
|
||||
<constraint firstAttribute="height" constant="50" id="kSM-fg-IHB"/>
|
||||
<constraint firstItem="bsq-3U-VjV" firstAttribute="top" secondItem="Zm7-AB-ZtE" secondAttribute="top" id="qpF-Za-XTL"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" keyboardDismissMode="onDrag" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="kNf-Ll-jvH">
|
||||
<rect key="frame" x="0.0" y="50" width="375" height="617"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="accessibilityIdentifier" value="StartChatVCTableView"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
<connections>
|
||||
<outlet property="dataSource" destination="-1" id="tlI-w1-VJw"/>
|
||||
<outlet property="delegate" destination="-1" id="xcS-Zy-x2X"/>
|
||||
</connections>
|
||||
</tableView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="trailing" secondItem="Zm7-AB-ZtE" secondAttribute="trailing" id="0W7-Iv-Cs1"/>
|
||||
<constraint firstAttribute="trailing" secondItem="kNf-Ll-jvH" secondAttribute="trailing" id="1KS-nO-Jys"/>
|
||||
<constraint firstItem="Zm7-AB-ZtE" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="Irh-6y-0cw"/>
|
||||
<constraint firstItem="kNf-Ll-jvH" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="hfq-4u-4J8"/>
|
||||
<constraint firstAttribute="bottom" secondItem="kNf-Ll-jvH" secondAttribute="bottom" id="jLY-ml-Psl"/>
|
||||
<constraint firstItem="Zm7-AB-ZtE" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="sUb-hD-qXJ"/>
|
||||
<constraint firstItem="kNf-Ll-jvH" firstAttribute="top" secondItem="Zm7-AB-ZtE" secondAttribute="bottom" id="tYv-VV-8dI"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</objects>
|
||||
</document>
|
||||
Reference in New Issue
Block a user