Rebranding: replace Vector by Riot everywhere in the git and github repos

- Rename categories
This commit is contained in:
Giom Foret 2017-03-09 11:50:28 +01:00
parent 7928cd5e47
commit 08c29911a7
6 changed files with 0 additions and 1296 deletions

View file

@ -1,94 +0,0 @@
/*
Copyright 2015 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 <MatrixKit/MatrixKit.h>
/**
Define a `MXRoom` category at Vector level.
*/
@interface MXRoom (Vector)
/**
The Riot displayname of the room
*/
@property(nonatomic, readonly) NSString* riotDisplayname;
/**
Tell whether all the notifications are disabled for the room.
*/
@property(nonatomic, readonly, getter=isMute) BOOL mute;
/**
Tell whether the regular notifications are disabled for the room.
*/
@property(nonatomic, readonly, getter=isMentionsOnly) BOOL mentionsOnly;
/*
Observer when a rules deletion fails.
*/
@property (nonatomic) id notificationCenterDidFailObserver;
/*
Observer when a rules deletion succeeds.
*/
@property (nonatomic) id notificationCenterDidUpdateObserver;
/**
Set the room avatar in the dedicated MXKImageView.
The vector style implies to use in order :
1 - the default avatar if there is one
2 - the member avatar for < 3 members rooms
3 - the first later of the room name.
@param mxkImageView the destinated MXKImageView.
*/
- (void)setRoomAvatarImageIn:(MXKImageView*)mxkImageView;
/**
Update the room tag.
@param tag the new tag value
@param completion the block to execute at the end of the operation (independently if it succeeded or not).
You may specify nil for this parameter.
*/
- (void)setRoomTag:(NSString*)tag completion:(void (^)())completion;
/**
Disable all the room notifications.
@param completion the block to execute at the end of the operation (independently if it succeeded or not).
You may specify nil for this parameter.
*/
- (void)mute:(void (^)())completion;
/**
Set the room notifications in mention only mode.
@param completion the block to execute at the end of the operation (independently if it succeeded or not).
You may specify nil for this parameter.
*/
- (void)mentionsOnly:(void (^)())completion;
/**
Enable the room notifications.
@param completion the block to execute at the end of the operation (independently if it succeeded or not).
You may specify nil for this parameter.
*/
- (void)allMessages:(void (^)())completion;
@end

View file

@ -1,791 +0,0 @@
/*
Copyright 2015 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 "MXRoom+Vector.h"
#import "AvatarGenerator.h"
#import <objc/runtime.h>
@implementation MXRoom (Vector)
#pragma mark - Room avatar
- (void)setRoomAvatarImageIn:(MXKImageView*)mxkImageView
{
NSString* roomAvatarUrl = self.state.avatar;
if (!roomAvatarUrl)
{
// If the room has only two members, use the avatar of the second member.
NSArray* members = self.state.members;
if (members.count == 2)
{
NSString* myUserId = self.mxSession.myUser.userId;
for (MXRoomMember *roomMember in members)
{
if (![roomMember.userId isEqualToString:myUserId])
{
// Use the avatar of this member only if he joined or he is invited.
if (MXMembershipJoin == roomMember.membership || MXMembershipInvite == roomMember.membership)
{
roomAvatarUrl = roomMember.avatarUrl;
}
break;
}
}
}
}
// Retrieve the Riot room display name to prepare the default avatar image.
// Note: this display name is nil for an "empty room" without display name (We name "empty room" a room in which the current user is the only active member).
NSString *avatarDisplayName = self.riotDisplayname;
UIImage* avatarImage = [AvatarGenerator generateAvatarForMatrixItem:self.state.roomId withDisplayName:avatarDisplayName];
if (roomAvatarUrl)
{
mxkImageView.enableInMemoryCache = YES;
[mxkImageView setImageURL:[self.mxSession.matrixRestClient urlOfContentThumbnail:roomAvatarUrl toFitViewSize:mxkImageView.frame.size withMethod:MXThumbnailingMethodCrop] withType:nil andImageOrientation:UIImageOrientationUp previewImage:avatarImage];
}
else
{
mxkImageView.image = avatarImage;
}
mxkImageView.contentMode = UIViewContentModeScaleAspectFill;
}
#pragma mark - Room display name
- (NSString *)riotDisplayname
{
// this algo is the one defined in
// https://github.com/matrix-org/matrix-js-sdk/blob/develop/lib/models/room.js#L617
// calculateRoomName(room, userId)
MXRoomState* roomState = self.state;
if (roomState.name.length > 0)
{
return roomState.name;
}
NSString *alias = roomState.canonicalAlias;
if (!alias)
{
// For rooms where canonical alias is not defined, we use the 1st alias as a workaround
NSArray *aliases = roomState.aliases;
if (aliases.count)
{
alias = [aliases[0] copy];
}
}
// check if there is non empty alias.
if ([alias length] > 0)
{
return alias;
}
NSString* myUserId = self.mxSession.myUser.userId;
NSArray* members = roomState.members;
NSMutableArray* othersActiveMembers = [[NSMutableArray alloc] init];
NSMutableArray* activeMembers = [[NSMutableArray alloc] init];
for(MXRoomMember* member in members)
{
if (member.membership != MXMembershipLeave)
{
if (![member.userId isEqualToString:myUserId])
{
[othersActiveMembers addObject:member];
}
[activeMembers addObject:member];
}
}
// sort the members by their creation (oldest first)
othersActiveMembers = [[othersActiveMembers sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
uint64_t originServerTs1 = 0;
uint64_t originServerTs2 = 0;
MXRoomMember* member1 = (MXRoomMember*)obj1;
MXRoomMember* member2 = (MXRoomMember*)obj2;
if (member1.originalEvent)
{
originServerTs1 = member1.originalEvent.originServerTs;
}
if (member2.originalEvent)
{
originServerTs2 = member2.originalEvent.originServerTs;
}
if (originServerTs1 == originServerTs2)
{
return NSOrderedSame;
}
else
{
return originServerTs1 > originServerTs2 ? NSOrderedDescending : NSOrderedAscending;
}
}] mutableCopy];
NSString* displayName = @"";
if (othersActiveMembers.count == 0)
{
if (activeMembers.count == 1)
{
MXRoomMember* member = [activeMembers objectAtIndex:0];
if (member.membership == MXMembershipInvite)
{
if (member.originalEvent.sender)
{
// extract who invited us to the room
displayName = [NSString stringWithFormat:NSLocalizedStringFromTable(@"room_displayname_invite_from", @"Vector", nil), [roomState memberName:member.originalEvent.sender]];
}
else
{
displayName = NSLocalizedStringFromTable(@"room_displayname_room_invite", @"Vector", nil);
}
}
}
}
else if (othersActiveMembers.count == 1)
{
MXRoomMember* member = [othersActiveMembers objectAtIndex:0];
displayName = [roomState memberName:member.userId];
}
else if (othersActiveMembers.count == 2)
{
MXRoomMember* member1 = [othersActiveMembers objectAtIndex:0];
MXRoomMember* member2 = [othersActiveMembers objectAtIndex:1];
displayName = [NSString stringWithFormat:NSLocalizedStringFromTable(@"room_displayname_two_members", @"Vector", nil), [roomState memberName:member1.userId], [roomState memberName:member2.userId]];
}
else
{
MXRoomMember* member = [othersActiveMembers objectAtIndex:0];
displayName = [NSString stringWithFormat:NSLocalizedStringFromTable(@"room_displayname_more_than_two_members", @"Vector", nil), [roomState memberName:member.userId], othersActiveMembers.count - 1];
}
return displayName;
}
#pragma mark - Room tags
- (void)setRoomTag:(NSString*)tag completion:(void (^)())completion
{
NSString* oldTag = nil;
if (self.accountData.tags && self.accountData.tags.count)
{
oldTag = [self.accountData.tags.allKeys objectAtIndex:0];
}
// support only kMXRoomTagFavourite or kMXRoomTagLowPriority tags by now
if (![tag isEqualToString:kMXRoomTagFavourite] && ![tag isEqualToString:kMXRoomTagLowPriority])
{
tag = nil;
}
NSString* tagOrder = [self.mxSession tagOrderToBeAtIndex:0 from:NSNotFound withTag:tag];
NSLog(@"[MXRoom+Vector] Update the room %@ tag from %@ to %@ with tag order %@", self.state.roomId, oldTag, tag, tagOrder);
[self replaceTag:oldTag
byTag:tag
withOrder:tagOrder
success: ^{
if (completion)
{
completion();
}
} failure:^(NSError *error) {
NSLog(@"[MXRoom+Vector] Failed to update the tag %@ of room (%@)", tag, self.state.roomId);
// Notify user
[[NSNotificationCenter defaultCenter] postNotificationName:kMXKErrorNotification object:error];
if (completion)
{
completion();
}
}];
}
#pragma mark - Room notification mode
- (BOOL)isMute
{
// Check whether an override rule has been defined with the roomm id as rule id.
// This kind of rule is created to mute the room
MXPushRule* rule = [self getOverrideRoomPushRule];
if (rule)
{
for (MXPushRuleAction *ruleAction in rule.actions)
{
if (ruleAction.actionType == MXPushRuleActionTypeDontNotify)
{
for (MXPushRuleCondition *ruleCondition in rule.conditions)
{
if (ruleCondition.kindType == MXPushRuleConditionTypeEventMatch)
{
NSString *key;
NSString *pattern;
MXJSONModelSetString(key, ruleCondition.parameters[@"key"]);
MXJSONModelSetString(pattern, ruleCondition.parameters[@"pattern"]);
if (key && pattern && [key isEqualToString:@"room_id"] && [pattern isEqualToString:self.state.roomId])
{
return rule.enabled;
}
}
}
}
}
}
return NO;
}
- (BOOL)isMentionsOnly
{
// Check push rules at room level
MXPushRule *rule = [self getRoomPushRule];
if (rule)
{
for (MXPushRuleAction *ruleAction in rule.actions)
{
if (ruleAction.actionType == MXPushRuleActionTypeDontNotify)
{
return rule.enabled;
}
}
}
return NO;
}
- (void)mute:(void (^)())completion
{
// Check the current notification mode
if (self.isMute)
{
if (completion)
{
completion();
}
return;
}
// Check whether a rule at room level must be removed first
if (self.isMentionsOnly)
{
MXPushRule* rule = [self getRoomPushRule];
[self removePushRule:rule completion:^{
[self mute:completion];
}];
return;
}
// The user does not want to have push at all
MXPushRule* rule = [self getOverrideRoomPushRule];
// Check if no rule is already defined.
if (!rule)
{
// Add a new one
[self addPushRuleToMute:completion];
}
else
{
// Check whether there is no pending update for this room
if (self.notificationCenterDidUpdateObserver)
{
NSLog(@"[MXRoom+Vector] Request in progress: ignore push rule update");
if (completion)
{
completion();
}
return;
}
// check if the user did not define one
BOOL hasDontNotifyRule = NO;
for (MXPushRuleAction *ruleAction in rule.actions)
{
if (ruleAction.actionType == MXPushRuleActionTypeDontNotify)
{
hasDontNotifyRule = YES;
break;
}
}
// if the user defined one, use it
if (hasDontNotifyRule)
{
[self enablePushRule:rule completion:completion];
}
else
{
// If the user has defined a room rule, the rule is deleted before adding new one.
[self removePushRule:rule completion:^{
// Add new rule to disable notification
[self addPushRuleToMute:completion];
}];
}
}
}
- (void)mentionsOnly:(void (^)())completion
{
// Check the current notification mode
if (self.isMentionsOnly)
{
if (completion)
{
completion();
}
return;
}
// Check whether an override rule must be removed first
if (self.mute)
{
MXPushRule* rule = [self getOverrideRoomPushRule];
[self removePushRule:rule completion:^{
[self mentionsOnly:completion];
}];
return;
}
// The user wants to have push only for highlighted notifications
MXPushRule* rule = [self getRoomPushRule];
// Check if no rule is already defined.
if (!rule)
{
// Add a new one
[self addPushRuleToMentionsOnly:completion];
}
else
{
// Check whether there is no pending update for this room
if (self.notificationCenterDidUpdateObserver)
{
NSLog(@"[MXRoom+Vector] Request in progress: ignore push rule update");
if (completion)
{
completion();
}
return;
}
// check if the user did not define one
BOOL hasDontNotifyRule = NO;
for (MXPushRuleAction *ruleAction in rule.actions)
{
if (ruleAction.actionType == MXPushRuleActionTypeDontNotify)
{
hasDontNotifyRule = YES;
break;
}
}
// if the user defined one, use it
if (hasDontNotifyRule)
{
[self enablePushRule:rule completion:completion];
}
else
{
// If the user has defined a room rule, the rule is deleted before adding new one.
[self removePushRule:rule completion:^{
// Add new rule to disable notification
[self addPushRuleToMentionsOnly:completion];
}];
}
}
}
- (void)allMessages:(void (^)())completion
{
// Check the current notification mode
if (!self.isMentionsOnly && !self.isMute)
{
// Nothing to do
if (completion)
{
completion();
}
return;
}
// Check whether an override rule must be removed first
if (self.isMute)
{
MXPushRule* rule = [self getOverrideRoomPushRule];
[self removePushRule:rule completion:^{
// Check the push rule at room level now
[self allMessages:completion];
}];
return;
}
// Check whether a rule at room level must be removed
if (self.isMentionsOnly)
{
MXPushRule* rule = [self getRoomPushRule];
[self removePushRule:rule completion:^{
// let the other notification rules manage the pushes.
[self removePushRule:rule completion:completion];
}];
}
}
#pragma mark -
- (MXPushRule*)getRoomPushRule
{
NSArray* rules = self.mxSession.notificationCenter.rules.global.room;
// sanity checks
if (rules)
{
for(MXPushRule* rule in rules)
{
// the rule id is the room Id
// it is the server trick to avoid duplicated rule on the same room.
if ([rule.ruleId isEqualToString:self.state.roomId])
{
return rule;
}
}
}
return nil;
}
- (MXPushRule*)getOverrideRoomPushRule
{
NSArray* rules = self.mxSession.notificationCenter.rules.global.override;
// sanity checks
if (rules)
{
for(MXPushRule* rule in rules)
{
// the rule id is the room Id
// it is the server trick to avoid duplicated rule on the same room.
if ([rule.ruleId isEqualToString:self.state.roomId])
{
return rule;
}
}
}
return nil;
}
- (void)addPushRuleToMentionsOnly:(void (^)())completion
{
MXNotificationCenter* notificationCenter = self.mxSession.notificationCenter;
// Define notificationCenter observers if a completion block is defined.
if (completion)
{
__weak typeof(self) weakSelf = self;
self.notificationCenterDidUpdateObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXNotificationCenterDidUpdateRules object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
// Check whether the rule has been added
BOOL isAdded = ([self getRoomPushRule] != nil);
if (isAdded)
{
__strong __typeof(weakSelf)strongSelf = weakSelf;
if (strongSelf.notificationCenterDidUpdateObserver)
{
[[NSNotificationCenter defaultCenter] removeObserver:strongSelf.notificationCenterDidUpdateObserver];
strongSelf.notificationCenterDidUpdateObserver = nil;
}
if (strongSelf.notificationCenterDidFailObserver)
{
[[NSNotificationCenter defaultCenter] removeObserver:strongSelf.notificationCenterDidFailObserver];
strongSelf.notificationCenterDidFailObserver = nil;
}
completion();
}
}];
self.notificationCenterDidFailObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXNotificationCenterDidFailRulesUpdate object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
__strong __typeof(weakSelf)strongSelf = weakSelf;
if (strongSelf.notificationCenterDidUpdateObserver)
{
[[NSNotificationCenter defaultCenter] removeObserver:strongSelf.notificationCenterDidUpdateObserver];
strongSelf.notificationCenterDidUpdateObserver = nil;
}
if (strongSelf.notificationCenterDidFailObserver)
{
[[NSNotificationCenter defaultCenter] removeObserver:strongSelf.notificationCenterDidFailObserver];
strongSelf.notificationCenterDidFailObserver = nil;
}
completion();
}];
}
[notificationCenter addRoomRule:self.state.roomId
notify:NO
sound:NO
highlight:NO];
}
- (void)addPushRuleToMute:(void (^)())completion
{
MXNotificationCenter* notificationCenter = self.mxSession.notificationCenter;
// Define notificationCenter observers if a completion block is defined.
if (completion)
{
__weak typeof(self) weakSelf = self;
self.notificationCenterDidUpdateObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXNotificationCenterDidUpdateRules object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
// Check whether the rule has been added
BOOL isAdded = ([self getOverrideRoomPushRule] != nil);
if (isAdded)
{
__strong __typeof(weakSelf)strongSelf = weakSelf;
if (strongSelf.notificationCenterDidUpdateObserver)
{
[[NSNotificationCenter defaultCenter] removeObserver:strongSelf.notificationCenterDidUpdateObserver];
strongSelf.notificationCenterDidUpdateObserver = nil;
}
if (strongSelf.notificationCenterDidFailObserver)
{
[[NSNotificationCenter defaultCenter] removeObserver:strongSelf.notificationCenterDidFailObserver];
strongSelf.notificationCenterDidFailObserver = nil;
}
completion();
}
}];
self.notificationCenterDidFailObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXNotificationCenterDidFailRulesUpdate object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
__strong __typeof(weakSelf)strongSelf = weakSelf;
if (strongSelf.notificationCenterDidUpdateObserver)
{
[[NSNotificationCenter defaultCenter] removeObserver:strongSelf.notificationCenterDidUpdateObserver];
strongSelf.notificationCenterDidUpdateObserver = nil;
}
if (strongSelf.notificationCenterDidFailObserver)
{
[[NSNotificationCenter defaultCenter] removeObserver:strongSelf.notificationCenterDidFailObserver];
strongSelf.notificationCenterDidFailObserver = nil;
}
completion();
}];
}
[notificationCenter addOverrideRuleWithId:self.state.roomId
conditions:@[@{@"kind":@"event_match", @"key":@"room_id", @"pattern":self.state.roomId}]
notify:NO
sound:NO
highlight:NO];
}
- (void)removePushRule:(MXPushRule *)rule completion:(void (^)())completion
{
MXNotificationCenter* notificationCenter = self.mxSession.notificationCenter;
// Define notificationCenter observers if a completion block is defined.
if (completion)
{
__weak typeof(self) weakSelf = self;
self.notificationCenterDidUpdateObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXNotificationCenterDidUpdateRules object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
// Check whether the rule has been removed
BOOL isRemoved = ([notificationCenter ruleById:rule.ruleId] == nil);
if (isRemoved)
{
__strong __typeof(weakSelf)strongSelf = weakSelf;
if (strongSelf.notificationCenterDidUpdateObserver)
{
[[NSNotificationCenter defaultCenter] removeObserver:strongSelf.notificationCenterDidUpdateObserver];
strongSelf.notificationCenterDidUpdateObserver = nil;
}
if (strongSelf.notificationCenterDidFailObserver)
{
[[NSNotificationCenter defaultCenter] removeObserver:strongSelf.notificationCenterDidFailObserver];
strongSelf.notificationCenterDidFailObserver = nil;
}
completion();
}
}];
self.notificationCenterDidFailObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXNotificationCenterDidFailRulesUpdate object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
__strong __typeof(weakSelf)strongSelf = weakSelf;
if (strongSelf.notificationCenterDidUpdateObserver)
{
[[NSNotificationCenter defaultCenter] removeObserver:strongSelf.notificationCenterDidUpdateObserver];
strongSelf.notificationCenterDidUpdateObserver = nil;
}
if (strongSelf.notificationCenterDidFailObserver)
{
[[NSNotificationCenter defaultCenter] removeObserver:strongSelf.notificationCenterDidFailObserver];
strongSelf.notificationCenterDidFailObserver = nil;
}
completion();
}];
}
[notificationCenter removeRule:rule];
}
- (void)enablePushRule:(MXPushRule *)rule completion:(void (^)())completion
{
MXNotificationCenter* notificationCenter = self.mxSession.notificationCenter;
// Define notificationCenter observers if a completion block is defined.
if (completion)
{
__weak typeof(self) weakSelf = self;
self.notificationCenterDidUpdateObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXNotificationCenterDidUpdateRules object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
// No way to check whether this notification concerns the push rule. Consider the change is applied.
__strong __typeof(weakSelf)strongSelf = weakSelf;
if (strongSelf.notificationCenterDidUpdateObserver)
{
[[NSNotificationCenter defaultCenter] removeObserver:strongSelf.notificationCenterDidUpdateObserver];
strongSelf.notificationCenterDidUpdateObserver = nil;
}
if (strongSelf.notificationCenterDidFailObserver)
{
[[NSNotificationCenter defaultCenter] removeObserver:strongSelf.notificationCenterDidFailObserver];
strongSelf.notificationCenterDidFailObserver = nil;
}
completion();
}];
self.notificationCenterDidFailObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXNotificationCenterDidFailRulesUpdate object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
__strong __typeof(weakSelf)strongSelf = weakSelf;
if (strongSelf.notificationCenterDidUpdateObserver)
{
[[NSNotificationCenter defaultCenter] removeObserver:strongSelf.notificationCenterDidUpdateObserver];
strongSelf.notificationCenterDidUpdateObserver = nil;
}
if (strongSelf.notificationCenterDidFailObserver)
{
[[NSNotificationCenter defaultCenter] removeObserver:strongSelf.notificationCenterDidFailObserver];
strongSelf.notificationCenterDidFailObserver = nil;
}
completion();
}];
}
[notificationCenter enableRule:rule isEnabled:YES];
}
- (void)setNotificationCenterDidFailObserver:(id)anObserver
{
objc_setAssociatedObject(self, @selector(notificationCenterDidFailObserver), anObserver, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (id)notificationCenterDidFailObserver
{
return objc_getAssociatedObject(self, @selector(notificationCenterDidFailObserver));
}
- (void)setNotificationCenterDidUpdateObserver:(id)anObserver
{
objc_setAssociatedObject(self, @selector(notificationCenterDidUpdateObserver), anObserver, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (id)notificationCenterDidUpdateObserver
{
return objc_getAssociatedObject(self, @selector(notificationCenterDidUpdateObserver));
}
@end

View file

@ -1,25 +0,0 @@
/*
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 <MatrixKit/MatrixKit.h>
/**
The `UINavigationController` category overrides the default auto rotation handling.
*/
@interface UINavigationController (Vector)
@end

View file

@ -1,51 +0,0 @@
/*
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 "UINavigationController+Vector.h"
@implementation UINavigationController (Vector)
- (BOOL)shouldAutorotate
{
if (self.topViewController)
{
return [self.topViewController shouldAutorotate];
}
return YES;
}
-(UIInterfaceOrientationMask)supportedInterfaceOrientations
{
if (self.topViewController)
{
return [self.topViewController supportedInterfaceOrientations];
}
return UIInterfaceOrientationMaskAll;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
if (self.topViewController)
{
return [self.topViewController preferredInterfaceOrientationForPresentation];
}
return UIInterfaceOrientationUnknown;
}
@end

View file

@ -1,66 +0,0 @@
/*
Copyright 2015 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 <MatrixKit/MatrixKit.h>
/**
The `VectorSearch` category adds the management of the search bar in Vector screens.
*/
@interface UIViewController (VectorSearch) <UISearchBarDelegate>
/**
The search bar.
*/
@property (nonatomic, readonly) UISearchBar *searchBar;
/**
The search bar state.
*/
@property (nonatomic, readonly) BOOL searchBarHidden;
/**
The Vector empty search background image (champagne bubbles).
The image adapts its width to its parent view width.
Its bottom is aligned to the top of the keyboard.
*/
@property (nonatomic, readonly) UIImageView *backgroundImageView;
@property (nonatomic, readonly) NSLayoutConstraint *backgroundImageViewBottomConstraint;
/**
Show/Hide the search bar.
@param animated or not.
*/
- (void)showSearch:(BOOL)animated;
- (void)hideSearch:(BOOL)animated;
/**
Initialise `backgroundImageView` and add it to the passed parent view.
@param view the view to add `backgroundImageView` to.
*/
- (void)addBackgroundImageViewToView:(UIView*)view;
/**
Provide the new height of the keyboard to align `backgroundImageView`
@param keyboardHeight the keyboard height.
*/
- (void)setKeyboardHeightForBackgroundImage:(CGFloat)keyboardHeight;
@end

View file

@ -1,269 +0,0 @@
/*
Copyright 2015 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 "UIViewController+VectorSearch.h"
#import <objc/runtime.h>
/**
`UIViewControllerVectorSearchInternals` is the internal single point storage for the search feature.
It hosts all required data so that only one associated object can be used in the category.
*/
@interface UIViewControllerVectorSearchInternals : NSObject
// The search bar
@property (nonatomic) UISearchBar *searchBar;
@property (nonatomic) BOOL searchBarHidden;
// Backup of view when displaying search
@property (nonatomic) UIView *backupTitleView;
@property (nonatomic) UIBarButtonItem *backupLeftBarButtonItem;
@property (nonatomic) UIBarButtonItem *backupRightBarButtonItem;
// The Vector empty search background image (champagne bubbles)
@property (nonatomic) UIImageView *backgroundImageView;
@property (nonatomic) NSLayoutConstraint *backgroundImageViewBottomConstraint;
@end
@implementation UIViewControllerVectorSearchInternals
@end
#pragma mark - UIViewController+VectorSearch
#pragma mark -
@interface UIViewController ()
// The single associated object hosting all data.
@property(nonatomic) UIViewControllerVectorSearchInternals *searchInternals;
@end
@implementation UIViewController (VectorSearch)
- (UISearchBar *)searchBar
{
return self.searchInternals.searchBar;
}
- (BOOL)searchBarHidden
{
return self.searchInternals.searchBarHidden;
}
- (UIImageView*)backgroundImageView
{
return self.searchInternals.backgroundImageView;
}
- (NSLayoutConstraint *)backgroundImageViewBottomConstraint
{
return self.searchInternals.backgroundImageViewBottomConstraint;
}
- (void)showSearch:(BOOL)animated
{
if (self.searchInternals.searchBarHidden)
{
// Backup screen header before displaying the search bar in it
self.searchInternals.backupTitleView = self.navigationItem.titleView;
self.searchInternals.backupLeftBarButtonItem = self.navigationItem.leftBarButtonItem;
self.searchInternals.backupRightBarButtonItem = self.navigationItem.rightBarButtonItem;
self.searchInternals.searchBarHidden = NO;
// Reset searches
self.searchBar.text = @"";
// Remove navigation buttons
self.navigationItem.hidesBackButton = YES;
self.navigationItem.rightBarButtonItem = nil;
self.navigationItem.leftBarButtonItem = nil;
// Add the search bar
self.navigationItem.titleView = self.searchBar;
// On iPad, there is no cancel button inside the UISearchBar
// So, add a classic cancel right bar button
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad)
{
UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(onIPadCancelPressed:)];
[self.navigationItem setRightBarButtonItem: cancelButton animated:YES];
}
}
// And display the keyboard
[self.searchBar becomeFirstResponder];
}
- (void)hideSearch:(BOOL)animated
{
if (!self.searchInternals.searchBarHidden)
{
// Restore the screen header
self.navigationItem.hidesBackButton = NO;
self.navigationItem.titleView = self.searchInternals.backupTitleView;
self.navigationItem.leftBarButtonItem = self.searchInternals.backupLeftBarButtonItem;
self.navigationItem.rightBarButtonItem = self.searchInternals.backupRightBarButtonItem;
self.searchInternals.searchBarHidden = YES;
}
}
- (void)addBackgroundImageViewToView:(UIView*)view
{
UIImageView *backgroundImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"search_bg"]];
backgroundImageView.translatesAutoresizingMaskIntoConstraints = NO;
[view addSubview:backgroundImageView];
// Keep it at left
NSLayoutConstraint *leftConstraint = [NSLayoutConstraint constraintWithItem:view
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:backgroundImageView
attribute:NSLayoutAttributeLeading
multiplier:1.0
constant:0];
// Same width as parent
NSLayoutConstraint *widthConstraint = [NSLayoutConstraint constraintWithItem:view
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:backgroundImageView
attribute:NSLayoutAttributeWidth
multiplier:1.0f
constant:0.0f];
// Keep the image aspect ratio
NSLayoutConstraint *aspectRatioConstraint = [NSLayoutConstraint
constraintWithItem:backgroundImageView
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:backgroundImageView
attribute:NSLayoutAttributeWidth
multiplier:(backgroundImageView.frame.size.height / backgroundImageView.frame.size.width)
constant:0];
// Set its position according to its bottom
NSLayoutConstraint *bottomConstraint = [NSLayoutConstraint constraintWithItem:view
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:backgroundImageView
attribute:NSLayoutAttributeBottom
multiplier:1.0f
constant:216];
[NSLayoutConstraint activateConstraints:@[leftConstraint,
widthConstraint,
aspectRatioConstraint,
bottomConstraint
]];
self.searchInternals.backgroundImageView = backgroundImageView;
self.searchInternals.backgroundImageViewBottomConstraint = bottomConstraint;
// It will be showed once the keyboard appears
backgroundImageView.hidden = YES;
}
- (void)setKeyboardHeightForBackgroundImage:(CGFloat)keyboardHeight
{
// keyboardHeight = 0 means no keyboard
if (keyboardHeight > 0)
{
self.searchInternals.backgroundImageView.hidden = NO;
// 60 = 18 + 42 from the Vector design
self.searchInternals.backgroundImageViewBottomConstraint.constant = keyboardHeight - 60;
}
else
{
// Hide the search
self.searchInternals.backgroundImageView.hidden = YES;
}
}
#pragma mark - UISearchBarDelegate
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar2
{
// "Search" key has been pressed
[self.searchBar resignFirstResponder];
}
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar2
{
[self hideSearch:YES];
}
- (BOOL)searchBarShouldEndEditing:(UISearchBar *)searchBar2
{
// Keep the search bar cancel button enabled even if the keyboard is not displayed
dispatch_async(dispatch_get_main_queue(), ^{
for (UIView *subView in self.searchBar.subviews)
{
for (UIView *view in subView.subviews)
{
if ([view isKindOfClass:[UIButton class]])
{
[(UIButton *)view setEnabled:YES];
}
}
}
});
return YES;
}
#pragma mark - Private methods
- (void)onIPadCancelPressed:(id)sender
{
// Mimic the same behavior as on iPhones and call the UISearchBar cancel delegate method
if ([self.searchBar.delegate respondsToSelector:@selector(searchBarCancelButtonClicked:)])
{
[self.searchBar.delegate searchBarCancelButtonClicked:self.searchBar];
}
}
#pragma mark - Internal associated object
- (void)setSearchInternals:(UIViewControllerVectorSearchInternals *)searchInternals
{
objc_setAssociatedObject(self, @selector(searchInternals), searchInternals, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (UIViewControllerVectorSearchInternals *)searchInternals
{
UIViewControllerVectorSearchInternals *searchInternals = objc_getAssociatedObject(self, @selector(searchInternals));
if (!searchInternals)
{
// Initialise internal data at the first call
searchInternals = [[UIViewControllerVectorSearchInternals alloc] init];
UISearchBar *searchBar = [[UISearchBar alloc] init];
searchBar.showsCancelButton = YES;
searchBar.delegate = (id<UISearchBarDelegate>)self;
searchInternals.searchBar = searchBar;
self.searchInternals = searchInternals;
self.searchInternals.searchBarHidden = YES;
}
return searchInternals;
}
@end